공공 쿠버네티스 클러스터 방화벽 기반 통신 시 발생한 트러블슈팅 기록
주피터 컨테이너를 생성해주는 Kubespawner를 활용하여 구축한 쿠버네티스 클러스터는 마스터 노드와 워커 노드가 별도의 방화벽 정책이 필요하지 않았다.
하지만, 공공 클러스터의 보안 정책에 따라 앞으로 추가되는 워커 노드들은 방화벽(https://kubernetes.io/docs/reference/networking/ports-and-protocols/)을 열어서 클러스터를 구성해야했다.
하지만, 주피터 컨테이너를 띄웠을때 이슈가 발생했다.
# k get pods -A |grep jeawoo0594-02-2mpqp9r1
jeawoo0594-02-2mpqp9r1 jupyter-jeawoo0594-2d02-2mpqp9r1 1/1 Running 0 2d1h
test1-01-es02mn3h 파드가 정상적으로 띄워지긴 했으나, 서비스에서 컨테이너에 접속을 할 수 없었다.(약 1분 가량만 켜지고 파드 죽음)
파드 내부에 접속하여 프로세스가 정상 동작하는 지 확인하였지만 아무 문제 없었다.
root@jupyter-xxxx:~# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 2022 ? 00:05:23 tini -g -- start-notebook.sh
root 6 1 0 2022 ? 00:00:00 sudo -E -H -u jovyan PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/s
jovyan 19 6 0 2022 ? 00:38:47 /opt/conda/bin/python /opt/conda/bin/jupyterhub-singleuser --ip=0.0.0.0
jovyan 38 19 0 2022 ? 00:09:49 /opt/conda/bin/python -m ipykernel_launcher -f /home/jovyan/.local/share/jupyter/runtime/kern
root 149 0 1 07:32 pts/0 00:00:00 /bin/bash
root 157 149 0 07:32 pts/0 00:00:00 ps -ef
주피터 프록시 로그 또한 라우팅 적용이 잘되었다.
# tail -f /var/log/jupyter_proxy.log
16:14:53.821 [ConfigProxy] info: Adding route /k8s/user/jeawoo0594-xx-xxxxx -> http://10.244.2.144:8888
16:14:53.821 [ConfigProxy] info: Route added /k8s/user/jeawoo0594-xx-xxxxx -> http://10.244.2.144:8888
마스터 노드에 띄운 jupyterhub 에서 파드의 가상 ip로 8888포트 통신이 안되는 이슈였다. (/var/log/jupyterhub.log)
# tail -f /var/log/jupyterhub.log
[W 2023-05-11 14:05:03.292 JupyterHub utils:226] Failed to connect to http://10.244.9.42:8888/k8s/user/jeawoo0594-02-2mpqp9r1/ ([Errno 110] Connection timed out)
[W 2023-05-11 14:05:15.580 JupyterHub utils:226] Failed to connect to http://10.244.9.42:8888/k8s/user/jeawoo0594-02-2mpqp9r1/ ([Errno 110] Connection timed out)
[W 2023-05-11 14:05:27.868 JupyterHub utils:226] Failed to connect to http://10.244.9.42:8888/k8s/user/jeawoo0594-02-2mpqp9r1/ ([Errno 110] Connection timed out)
[W 2023-05-11 14:05:40.156 JupyterHub utils:226] Failed to connect to http://10.244.9.42:8888/k8s/user/jeawoo0594-02-2mpqp9r1/ ([Errno 110] Connection timed out)
따라서, 나는 먼저 마스터 노드에서 nc로 해당 pod의 가상 ip에 8888포트로 통신이 안되는 것을 확인했다.(참고로, 다른 기존 EPG존의 워커노드의 파드는 8888포트 통신이 된다)
워커노드의 가상 ip 는 마스터 노드에서 관리가 될텐데....라고 생각하며 ifconfig로 네트워크 구성을 열어보았지만 잘못 짚었다.
flannel.1 Link encap:Ethernet HWaddr xx:xx:xx:x:xx:xx
inet addr:10.244.0.0 Bcast:0.0.0.0 Mask:255.255.255.255
inet6 addr: ...
...
또한, 워커노드에도 ifconfig로 네트워크 구성을 열어보았으며 해당 워커노드에는 flannel 네트워크 인터페이스가 정상적으로 등록이 되었다.
해당 워커노드에서 해당 파드의 가상 아이피로 telnet 쐈을때에는 정상 통신이 된다.
root@KUBE-WORKER-002:# telnet 10.244.9.42 8888
Trying 10.244.9.42...
Connected to 10.244.9.42.
Escape character is '^]'.
HTTP/1.1 400 Bad Request
Connection closed by foreign host.
그렇다면, 지금 문제 상황을 다시 한번 정리해보자.
1. 파드는 정상적으로 생성되었고 컨테이너도 정상동작한다.
2. 마스터노드의 주피터허브 서버에서 pod-ip:8888 통신이 안된다.
3. 분명 네트워크 인터페이스는 등록이 되었다.
워커 노드는 kubelet을 통해 요청을 받고 kube-proxy는 워커 노드로 들어온 요청을 알맞게 각 파드의 가상 ip로 로드밸런싱해준다.
먼저, 워커 노드의 kubelet 로그를 봤다.
36607로 들어온 요청이 34910, 37560으로 포트 포워딩이 정상적으로 동작하지않는다는 것을 확인했다.
# journalctl -u kubelet -f -n 1000
May 11 14:03:57 KUBE-WORKER-002 kubelet[15475]: E0511 14:03:57.870756 15475 conn.go:254] Error on socket receive: read tcp 127.0.0.1:36607->127.0.0.1:34910: use of closed network connection
May 11 14:04:01 KUBE-WORKER-002 kubelet[15475]: E0511 14:04:01.694234 15475 conn.go:254] Error on socket receive: read tcp 127.0.0.1:36607->127.0.0.1:37560: use of closed network connection
36607은 kubelet 프로세스인것을 확인했다.
# netstat -nltp |grep 36607
tcp 0 0 127.0.0.1:36607 0.0.0.0:* LISTEN 15475/kubelet
그렇다면, 포트포워딩이 제대로 이뤄지지않은것은 kube-proxy 의 로그를 살펴보았다.
# crictl logs 1f5e7503a5279 -f -n 10000
WARN[0000] runtime connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
W0510 07:58:37.390459 1 server_others.go:329] Flag proxy-mode="" unknown, assuming iptables proxy
I0510 07:58:37.397144 1 node.go:135] Successfully retrieved node IP: 10.xxx.xx.x
I0510 07:58:37.397169 1 server_others.go:149] Using iptables Proxier.
W0510 07:58:37.397259 1 proxier.go:287] clusterCIDR not specified, unable to distinguish between internal and external traffic
unable to distinguish between internal and external traffic 이라는 오류가 한눈에 들어왔다.
"clusterCIDR not specified, unable to distinguish between internal and external traffic" 오류는 클러스터의 CIDR(클러스터 내부 IP 대역)가 지정되지 않아 내부 및 외부 트래픽을 구분할 수 없을 때 발생하는 문제이다.
해결
기존 네트워크 제한없는 워커노드에서 ip route 리눅스 명령어로 현재 등록된 라우팅 테이블을 조회하면 아래와 같이 나옵니다. 10.244.0.0은 마스터 노드의 flannel ip 대역대이고 나머지는 워커노드들의 flannel ip 대역이고, 10.244.3.0이 현재 워커노드의 flannel ip 대역입니다.
10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
10.244.3.0/24 dev cni0 proto kernel scope link src 10.244.3.1
하지만, 방화벽 기반 통신으로 join 하려는 워커 노드에서 ip route 로 현재 라우팅 테이블을 조회하면 위와 같이 라우팅 테이블에 CNI의 가상IP가 등록되어 있지 않았습니다.
이유는 너무 단순했습니다. flannel UDP protocol 8472 포트 개방을 누락했던 것이었습니다.
flannel CNI를 적용할때, VXLAN overlay로 구현했는데, 기본적으로 VXLAN은 flannel 인터페이스를 이용해서 UDP 프로토콜로 출발지, 도착지 pod식별정보(IP 등)을 capsulizing&decapsulizing을 하는 것이었습니다.
따라서, 해당 포트 통신을 마스터, 워커 상호간에 적용을 해주었고 문제를 해결할 수 있었습니다.