ESXi VMXNET3 환경의 MetalLB webhook timeout 해결

발생현상
MetalLB 설치 후 IPAddressPool 생성 시 admission webhook timeout이 발생했다.
Calico VXLAN 패킷에서 checksum 오류를 확인했다. Offload 설정을 변경하자 checksum 오류는 줄었지만, webhook timeout은 지속됐다.
최종적으로 VMware 가상 NIC를 VMXNET3에서 E1000E로 교체한 뒤 webhook 통신이 복구됐다.
1. 환경과 증상
구성 환경
| 항목 | 구성 |
|---|---|
| 가상화 플랫폼 | VMware ESXi |
| Linux 커널 | 5.14.0-687.54.1.el9_8.x86_64 |
| 기존 가상 NIC | VMXNET3 |
| NIC 드라이버 | vmxnet3, 1.9.0.0-k-NAPI |
| CNI | Calico |
| Pod CIDR | 10.233.64.0/18 |
| 캡슐화 | VXLAN Always |
| VXLAN 설정 | UDP4789, VNI 4096, MTU 1450 |
| MetalLB | v0.16.1, Helm 설치 |
| 네임스페이스 | metallb |
| 광고 방식 | L2 |
발생 오류
kubectl apply -f pool.yml
failed calling webhook "ipaddresspoolvalidationwebhook.metallb.io":
failed to call webhook:
Post "[https://metallb-webhook-service.metallb.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s](https://metallb-webhook-service.metallb.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s)":
context deadline exceeded
L2Advertisement 생성도 동일하게 실패했다.
failed calling webhook "l2advertisementvalidationwebhook.metallb.io"
context deadline exceeded
당시 통신 상태:
| 경로 | 결과 |
|---|---|
| Ingress → 애플리케이션 | 정상 |
| Worker → MetalLB controller Pod | 정상 |
| Master → MetalLB controller Pod | Timeout |
| Master → MetalLB webhook Service | Timeout |
문제가 발생한 경로는 다음과 같다.
kubectl apply
→ kube-apiserver
→ MetalLB webhook Service
→ worker의 MetalLB controller Pod
2. 진단 과정
Pod와 Service 확인
kubectl -n metallb get pods -o wide
kubectl -n metallb get svc metallb-webhook-service -o yaml
kubectl -n metallb get endpointslices \
-l kubernetes.io/service-name=metallb-webhook-service \
-o yaml
| 항목 | 확인 결과 |
|---|---|
| Controller 상태 | 1/1 Running, 재시작 없음 |
| Controller Pod IP | 10.233.103.150 |
| Webhook Service IP | 10.233.37.54 |
| Service 포트 | TCP443 |
| Endpoint 포트 | TCP9443 |
| Endpoint 상태 | ready: true, serving: true |
10.233.37.54:443
→ 10.233.103.150:9443
Controller 로그에서도 인증서 준비와 webhook 기동 완료를 확인했다.
certs are ready in /tmp/k8s-webhook-server/serving-certs
CA certs are injected to webhooks
Starting webhook server
Serving webhook server ... port: 9443
노드별 접속 테스트
Master와 worker에서 동일한 Pod IP로 접속했다.
curl -vk --noproxy '*' \
--connect-timeout 3 --max-time 5 \
[https://10.233.103.150:9443/](https://10.233.103.150:9443/)
Master 결과:
Trying 10.233.103.150:9443...
Connection timed out after 3001 milliseconds
Worker 결과:
Connected to 10.233.103.150 port 9443
SSL connection using TLSv1.3
HTTP/1.1 404 Not Found
Worker에서는 TCP 연결, TLS handshake, HTTP 응답까지 정상 진행됐다. / 경로의 404는 연결 실패가 아니다.
Master에서는 Service IP 접속도 실패했다.
curl -vk --noproxy '*' \
--connect-timeout 3 --max-time 5 \
[https://10.233.37.54:443/](https://10.233.37.54:443/)
Calico 경로 확인
kubectl get ippools.crd.projectcalico.org -o yaml
spec:
cidr: 10.233.64.0/18
ipipMode: Never
vxlanMode: Always
natOutgoing: true
라우트와 VXLAN 매핑도 확인했다.
ip route get 10.233.103.150
ip -d link show vxlan.calico
ip neigh show dev vxlan.calico
bridge fdb show dev vxlan.calico
Master의 목적지 경로:
10.233.103.150 via 10.233.103.128 dev vxlan.calico
src 10.233.106.128
라우트와 Neighbor/FDB는 존재했지만, 실제 통신은 실패했다.
패킷과 오류 카운터 확인
Worker에서 패킷을 캡처한 뒤 Master에서 curl을 실행했다.
sudo tcpdump -lni any -nn -vv \
'(host 192.168.100.11 and udp port 4789) or
(host 10.233.103.150 and tcp port 9443)'
eth0 In
192.168.100.11 → 192.168.0.22:4789
[bad udp cksum]
내부 TCP:
10.233.106.128 → 10.233.103.150:9443
Flags [S], incorrect checksum
SYN 재전송은 확인됐지만 SYN-ACK은 없었다.
nstat -az | grep -E 'UdpInErrors|UdpInCsumErrors'
ip -s link show vxlan.calico
| 항목 | 요청 전 | 요청 후 |
|---|---|---|
UdpInErrors |
1608 | 1610 |
UdpInCsumErrors |
1608 | 1610 |
| VXLAN RX packets | 12 | 12 |
캡처 결과와 커널 카운터 증가를 함께 확인해 VXLAN 수신 checksum 문제를 좁혔다.
추가 확인 결과:
- Kubernetes·Calico NetworkPolicy 없음.
- Calico HostEndpoint 없음.
- 해당 환경에서 방화벽과 SELinux 미사용.
- Worker의 IP forwarding 활성화.
- 역방향 검사 드롭 카운터 증가 없음.
3. 조치와 해결
Offload 변경: 해결되지 않음
변경 전 설정을 저장했다.
sudo ethtool -k eth0 > /tmp/eth0-offload-before.txt
sudo ethtool -k vxlan.calico > /tmp/vxlan-offload-before.txt
테스트 과정에서 다음 기능을 비활성화했다.
sudo ethtool -K eth0 \
tx-udp_tnl-segmentation off \
tx-udp_tnl-csum-segmentation off
sudo ethtool -K eth0 \
tx-checksum-ip-generic off
sudo ethtool -K vxlan.calico \
tx-checksum-ip-generic off
적용 상태를 확인했다.
sudo ethtool -k eth0 | grep -E \
'tx-checksum-ip-generic|tx-udp_tnl'
sudo ethtool -k vxlan.calico | grep \
tx-checksum-ip-generic
변경 후 결과:
| 항목 | 요청 전 | 요청 후 |
|---|---|---|
UdpInErrors |
1610 | 1610 |
UdpInCsumErrors |
1610 | 1610 |
| VXLAN RX packets | 23 | 25 |
vxlan.calico에서 내부 SYN도 관찰됐다.
vxlan.calico In
10.233.106.128 → 10.233.103.150:9443
Flags [S]
그러나 Pod 방향 전달은 확인되지 않았고, curl과 webhook timeout도 지속됐다.
Offload 변경은 checksum 오류를 개선했지만, 장애를 해결하지 못했다.
가상 NIC 교체: 통신 복구
최종 조치는 VMware 가상 NIC 교체였다.
VMXNET3 → E1000E
작업 순서:
- vSphere 콘솔 접근 확보.
- 기존 MAC, Port Group, IP, 라우팅, NetworkManager 프로파일 기록.
- VM 정상 종료.
- 가상 NIC를 E1000E로 교체.
- Port Group 연결 확인 후 부팅.
- 인터페이스와 노드 상태 확인.
- MetalLB Pool 설정 재적용.
변경 전후 확인 명령:
ip -br addr
ip route
nmcli -f NAME,UUID,DEVICE connection show
sudo ethtool -i <실제-인터페이스>
kubectl get nodes -o wide
kubectl -n kube-system get pods -o wide
kubectl -n metallb get pods -o wide
NIC 교체 후 pool.yml을 다시 적용했다.
kubectl apply -f pool.yml
이번에는 timeout 대신 설정 검증 오류가 반환됐다.
l2advertisement.metallb.io/vip-l2 created
admission webhook "ipaddresspoolvalidationwebhook.metallb.io"
denied the request:
parsing address pool vip-pool:
invalid CIDR "192.168.0.100"
| 변경 전 | NIC 교체 후 |
|---|---|
| Webhook 호출 timeout | Webhook 검증 응답 반환 |
| 요청·응답 통신 실패 | Pool 주소 형식 오류 확인 |
이 응답으로 API Server와 webhook 사이의 왕복 통신 복구를 확인했다.
4. Pool 설정 수정
통신 복구 후 확인된 오류는 Pool 주소 형식이었다.
addresses:
- "192.168.0.100"
이번에는 IP 범위로 수정했다.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: vip-pool
namespace: metallb
spec:
addresses:
- "192.168.0.100-192.168.0.110"
autoAssign: true
***
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: vip-l2
namespace: metallb
spec:
ipAddressPools:
- vip-pool
kubectl apply -f pool.yml
kubectl -n metallb get ipaddresspool,l2advertisement
이번 장애에서 관찰한 오류와 조치를 구분하면 다음과 같다.
| 구분 | 관찰 결과 | 조치 결과 |
|---|---|---|
| VXLAN checksum 오류 | UDP 수신 오류 카운터 증가 | Offload 변경 후 증가 중단 |
| Webhook timeout | Master에서 controller Pod 접속 실패 | VMXNET3 → E1000E 교체 후 복구 |
| Pool 형식 오류 | invalid CIDR 반환 |
IP 범위 형식으로 수정 |
이번 환경의 webhook timeout 해결책은 VMware 가상 NIC 교체였다.
정확한 내부 버그는 식별하지 못했지만, Offload 변경만으로는 해결되지 않았고 E1000E 교체 후 통신이 복구됐다.
Reference
- Choosing a network adapter for a virtual machine
- RSS and multiqueue support in Linux driver for VMXNET3
- VXLAN: bad UDP checksums
- Intermittent packet drops for dual VXLAN and Geneve encapsulated packets
- VM VXLAN traffic fails on a host prepared for NSX