이 페이지에서는 클러스터의 연결 문제를 해결하는 방법을 보여줍니다.
GKE에서 네트워크 패킷 캡처와 관련된 연결 문제
이 섹션에서는 연결 시간 초과, 연결 거부 오류, 예기치 않은 애플리케이션 동작과 같은 증상을 비롯하여 네트워크 패킷 캡처와 관련된 연결 문제를 해결하는 방법을 설명합니다. 이러한 연결 문제는 노드 수준 또는 포드 수준에서 발생할 수 있습니다.
클러스터 네트워크의 연결 문제는 대개 다음 카테고리에 속합니다.
- 포드에 연결할 수 없음: 네트워크 구성이 잘못되어 클러스터 안팎에서 포드에 액세스할 수 없을 수 있습니다.
- 서비스 중단: 서비스에 중단 또는 지연이 발생할 수 있습니다.
- 포드 간 통신 문제: 포드가 서로 효과적으로 통신하지 못할 수 있습니다.
GKE 클러스터의 연결 문제는 다음과 같은 다양한 원인으로 인해 발생할 수 있습니다.
- 네트워크 구성 오류: 잘못된 네트워크 정책, 방화벽 규칙 또는 라우팅 테이블
- 애플리케이션 버그: 네트워크 상호작용에 영향을 미치는 애플리케이션 코드의 오류
- 인프라 문제: 네트워크 정체, 하드웨어 오류 또는 리소스 제한
다음 섹션에서는 문제가 있는 노드 또는 포드의 문제를 해결하는 방법을 보여줍니다.
다음 명령어를 사용하여 문제가 있는 포드가 실행 중인 노드를 식별합니다.
kubectl get pods POD_NAME -o=wide -n NAMESPACE
다음을 바꿉니다.
POD_NAME
을 포드 이름으로 바꿉니다.NAMESPACE
를 Kubernetes 네임스페이스로 바꿉니다.
노드에 연결합니다.
gcloud compute ssh NODE_NAME \ --zone=ZONE
다음을 바꿉니다.
NODE_NAME
: 노드 이름입니다.ZONE
: 노드가 실행되는 영역의 이름입니다.
특정 포드를 디버깅하려면 포드와 연결된
veth
인터페이스를 확인합니다.ip route | grep POD_IP
POD_IP
를 포드 IP 주소로 바꿉니다.도구 상자 명령어를 실행합니다.
toolbox
명령어
toolbox
는 디버깅 및 문제 해결을 위해 GKE 노드 내에 컨테이너화된 환경을 제공하는 유틸리티입니다. 이 섹션에서는 toolbox
유틸리티를 설치하고 이를 사용하여 노드 문제를 해결하는 방법을 설명합니다.
노드에 연결된 동안
toolbox
도구를 시작합니다.toolbox
이렇게 하면
toolbox
유틸리티를 지원하는 파일이 다운로드됩니다.toolbox
루트 프롬프트에서tcpdump
를 설치합니다.외부 IP 주소 또는 Cloud NAT가 있는 클러스터의 경우:
apt update -y && apt install -y tcpdump
Cloud NAT가 없는 비공개 클러스터의 경우:
Cloud NAT가 없는 비공개 클러스터가 있는 경우
apt
를 사용하여tcpdump
를 설치할 수 없습니다. 대신 공식 저장소에서libpcap
및tcpdump
출시 파일을 다운로드하고gcloud compute scp
또는gsutil
을 사용하여 파일을 VM에 복사합니다. 그런 다음 아래 단계에 따라 라이브러리를 수동으로 설치합니다.cp /media/root/home/USER_NAME/tcpdump-VERSION.tar.gz /usr/sbin/ cp /media/root/home/USER_NAME/libpcap-VERSION.tar.gz /usr/sbin/ cd /usr/sbin/ tar -xvzf tcpdump-VERSION.tar.gz tar -xvzf libpcap-VERSION.tar.gz cd libpcap-VERSION ./configure ; make ; make install cd ../tcpdump-VERSION ./configure ; make ; make install tcpdump --version
다음을 바꿉니다.
USER_NAME
: 파일이 있는 시스템의 사용자 이름입니다.VERSION
:tcpdump
및libpcap
패키지의 특정 버전 번호입니다.
패킷 캡처를 시작합니다.
tcpdump -i eth0 -s 100 "port PORT" \ -w /media/root/mnt/stateful_partition/CAPTURE_FILE_NAME
다음을 바꿉니다.
PORT
: 포트 번호의 이름입니다.CAPTURE_FILE_NAME
: 캡처 파일의 이름입니다.
패킷 캡처를 중지하고
tcpdump
를 중단합니다.exit
를 입력하여 도구 상자를 닫습니다.패킷 캡처 파일을 나열하고 크기를 확인합니다.
ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
노드에서 패킷 캡처를 컴퓨터의 현재 작업 디렉터리로 복사합니다.
gcloud compute scp NODE_NAME:/mnt/stateful_partition/CAPTURE_FILE_NAME \ --zone=ZONE
다음을 바꿉니다.
NODE_NAME
: 노드 이름입니다.CAPTURE_FILE_NAME
: 캡처 파일의 이름입니다.ZONE
: 영역 이름입니다.
대체 명령어
다음 방법을 사용하여 문제가 있는 포드의 연결 문제를 해결할 수도 있습니다.
포드 컨테이너에 연결된 임시 디버그 워크로드
kubectl exec
를 사용하여 대상 포드에서 직접 셸을 실행한 다음tcpdump
명령어를 설치하고 실행합니다.
포드 네트워크 연결 문제
네트워크 개요 설명에서 언급한 것처럼, 효율적인 문제 해결을 위해서는 네트워크 네임스페이스에서 노드의 루트 네임스페이스로 포드가 연결된 방법을 이해하는 것이 중요합니다. 아래의 설명에서는 특별히 언급하지 않는 한 클러스터가 Calico 대신 GKE의 기본 CNI를 사용한다고 가정합니다. 즉, 네트워크 정책이 적용되지 않습니다.
선택 노드의 포드에 가용성 없음
선택 노드의 Pod에 네트워크 연결이 없으면 Linux 브리지가 작동 중인지 확인합니다.
ip address show cbr0
Linux 브리지가 작동 중지되었으면 다음 방법으로 작동시킵니다.
sudo ip link set cbr0 up
노드가 cbr0에 연결된 Pod MAC 주소를 학습하는지 확인합니다.
arp -an
선택 노드의 Pod에 최소 연결이 포함됨
선택 노드의 Pod에 최소 연결이 포함된 경우 먼저 도구 상자 컨테이너에서 tcpdump
를 실행하여 손실된 패킷이 있는지 여부를 확인해야 합니다.
sudo toolbox bash
아직 설치하지 않았으면 도구 상자에서 tcpdump
를 설치합니다.
apt install -y tcpdump
cbr0에 대해 tcpdump
를 실행합니다.
tcpdump -ni cbr0 host HOSTNAME and port PORT_NUMBER and [TCP|UDP|ICMP]
브리지에서 큰 패킷이 다운스트림으로 삭제된 것으로 나타나면(예: TCP 핸드셰이크가 완료되었지만 SSL hello가 수신되지 않음) 각 Linux 포드 인터페이스의 MTU가 클러스터 VPC 네트워크의 MTU로 올바르게 설정되었는지 확인합니다.
ip address show cbr0
오버레이가 사용된 경우(예: Weave 또는 Flannel), 오버레이의 캡슐화 오버헤드를 수용하도록 이 MTU를 더 줄여야 합니다.
GKE MTU
포드 인터페이스로 선택된 MTU는 클러스터 노드 및 기본 VPC MTU 설정에 사용되는 컨테이너 네트워크 인터페이스(CNI)에 따라 달라집니다. 자세한 내용은 포드를 참조하세요.
포드 인터페이스 MTU 값은 1460
이거나 노드의 기본 인터페이스에서 상속됩니다.
CNI | MTU | GKE Standard |
---|---|---|
kubenet | 1460 | 기본값 |
kubenet (GKE 버전 1.26.1 이상) |
상속됨 | 기본값 |
Calico | 1460 |
자세한 내용은 네트워크 정책을 사용한 포드 및 서비스 간 통신 제어를 참조하세요. |
netd | 상속됨 | 다음 중 하나를 사용하여 사용 설정됩니다. |
GKE Dataplane V2 | 상속됨 |
자세한 내용은 GKE Dataplane V2 사용을 참조하세요. |
간헐적인 연결 오류
포드에 대한 연결은 iptable에 의해 전달됩니다. 흐름은 conntrack 테이블의 항목으로 추적되며, 노드당 작업 부하가 많은 경우, conntrack 테이블 소진이 오류로 나타날 수 있습니다. 이러한 문제는 노드의 직렬 콘솔에 로깅될 수 있습니다. 예를 들면 다음과 같습니다.
nf_conntrack: table full, dropping packet
간헐적인 문제가 conntrack 소진으로 인해 발생한다는 사실을 확인할 수 있으면 클러스터 크기를 늘리거나(따라서 노드당 워크로드 및 흐름의 수를 줄이거나) nf_conntrack_max
를 늘릴 수 있습니다.
new_ct_max=$(awk '$1 == "MemTotal:" { printf "%d\n", $2/32; exit; }' /proc/meminfo)
sysctl -w net.netfilter.nf_conntrack_max="${new_ct_max:?}" \
&& echo "net.netfilter.nf_conntrack_max=${new_ct_max:?}" >> /etc/sysctl.conf
또한 NodeLocal DNSCache를 사용하여 연결 추적 항목을 줄일 수 있습니다.
컨테이너에 대해 'bind: Address already in use'가 보고됨
컨테이너 로그에 따라 애플리케이션이 바인딩하려는 포트가 이미 예약되었기 때문에 포드의 컨테이너를 시작할 수 없습니다. 컨테이너에 비정상 종료 루프가 발생 합니다. 예를 들어 Cloud Logging에서 다음이 발생합니다.
resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"
2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use
Docker가 충돌할 때 일부 경우에는 실행 중인 컨테이너가 뒤쳐져서 오래된 상태가 될 수 있습니다. 프로세스는 포드에 할당된 네트워크 네임스페이스에서 계속 실행 중이며, 해당 포트에서 수신 대기 중입니다. Docker 및 kubelet은 오래된 컨테이너를 모르므로 새 프로세스로 새 컨테이너를 시작하려 합니다. 따라서 이미 Pod와 연결된 네트워크 네임스페이스에 추가될 때 포트에서 결합할 수 없습니다.
이 문제를 진단하려면 다음 안내를 따르세요.
.metadata.uuid
필드에 Pod의 UUID가 필요합니다.kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg name UUID ubuntu-6948dd5657-4gsgg db9ed086-edba-11e8-bdd6-42010a800164
노드에서 다음 명령어의 출력을 가져옵니다.
docker ps -a ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
이 Pod에서 실행 중인 프로세스를 확인합니다. cgroup 네임스페이스의 UUID에는 Pod의 UUID가 포함되어 있으므로
ps
출력에서 Pod UUID에 grep을 실행할 수 있습니다. 앞의 라인에도 grep을 수행하므로docker-containerd-shim
프로세스가 컨테이너 ID를 인수에 지정하게 됩니다. 출력이 더 간단해지도록 cgroup 열의 나머지 부분을 잘라냅니다.# ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/ 1283089 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim 276e173b0846e24b704d4 12: 1283107 1283089 Ss sys_pause 4026532393 pause /pause 12: 1283150 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim ab4c7762f5abf40951770 12: 1283169 1283150 Ss do_wait 4026532393 sh /bin/sh -c echo hello && sleep 6000000 12: 1283185 1283169 S hrtimer_nanosleep 4026532393 sleep sleep 6000000 12: 1283244 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim 44e76e50e5ef4156fd5d3 12: 1283263 1283244 Ss sigsuspend 4026532393 nginx nginx: master process nginx -g daemon off; 12: 1283282 1283263 S ep_poll 4026532393 nginx nginx: worker process
이 목록에서
docker ps
에도 표시되는 컨테이너 ID를 확인할 수 있습니다.주요 내용은 다음과 같습니다.
docker-containerd-shim 276e173b0846e24b704d4
- 일시 중지docker-containerd-shim ab4c7762f5abf40951770
- sleep을 포함한 sh(sleep-ctr)docker-containerd-shim 44e76e50e5ef4156fd5d3
- nginx(echoserver-ctr)
docker ps
출력에서 해당 부분을 확인합니다.# docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3' 44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc "nginx -g 'daemon off;'" 14 hours ago Up 14 hours k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0 ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475 ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78 "/bin/sh -c 'echo hello && sleep 6000000'" 14 hours ago Up 14 hours k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0 276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327 registry.k8s.io/pause-amd64:3.1
일반적인 경우에는
ps
의 모든 컨테이너 ID가docker ps
에 표시됩니다. 표시되지 않은 항목이 있으면 이는 오래된 컨테이너이고, 이미 사용 중인 것으로 보고되는 TCP 포트에서 리슨 중인docker-containerd-shim process
의 하위 프로세스가 표시됩니다.이를 확인하려면 컨테이너의 네트워크 네임스페이스에서
netstat
을 실행합니다. Pod에서 모든 컨테이너 프로세스의 pid(docker-containerd-shim
아님)를 가져옵니다.앞의 예시:
- 1283107 - pause
- 1283169 - sh
- 1283185 - sleep
- 1283263 - nginx master
- 1283282 - nginx worker
# nsenter -t 1283107 --net netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast
또한
ip netns
를 사용하여netstat
을 실행할 수도 있지만 Docker가 연결을 수행하고 있지 않으므로 프로세스의 네트워크 네임스페이스를 수동으로 연결해야 합니다.# ln -s /proc/1283169/ns/net /var/run/netns/1283169 gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list 1283169 (id: 2) gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169
완화 방법:
단기적인 완화 방법은 앞에서 설명한 방법으로 비활성 프로세스를 식별하고 kill [PID]
명령어를 사용하여 프로세스를 종료하는 것입니다.
장기적인 완화 방법은 Docker가 충돌하는 원인을 식별하고 해결하는 것입니다. 가능한 이유는 다음과 같습니다.
- 좀비 프로세스 누적으로 인한 PID 네임스페이스 부족
- docker 버그
- 리소스 압력/OOM
다음 단계
- Kubernetes DNS 문제 진단에 대한 일반적인 정보는 DNS 변환 디버깅을 참조하세요.