티스토리 뷰

1. 문제 설명

kubectl 커맨드가 정상적으로 실행되다가 어느 순간 다시 아래와 같이 connection이 refused 되는 문제가 발생했다. 약 3~5분 간격으로 API 서버가 죽고, controller-namager나 scheduler도 죽었다 살아나기를 반복한다.

 

root@master:~# kubectl get nodes
the connection to the server <IP>:6443 was refused - did you specify the right host or port

 

모든 kubectl 커맨드는 API 서버로 가기 때문에 API 서버에 문제가 있을 거라 생각했다. kubectl 커맨드가 정상적으로 실행되지 않았기 때문에 API 서버를 포함한 쿠버네티스 컴포넌트들이 잘 실행 중인지 확인하기 위해 아래와 같이 netstat 커맨드를 사용했다.

 

cf. 5분 간격으로 실행한 netstat 커맨드 결과

위와 같이, 아무런 커맨드를 실행시키지 않았는데도 쿠버네티스 컴포넌트들이 사라졌다 다시 생겼다를 반복하고 있다. 

 

 

cf. master 노드 상태

- Virtual Box VM, ubuntu 22.04(kernel v5.15), 2 core, 4GB memory

- kubectl v1.25.0

- 쿠버네티스 구축: kubeadm(v1.25.0) 사용

- docker v20.10.17

- containerd v1.6.6 (runC v1.1.2)

- 쿠버네티스 설치: kubeadm 이용

- 방화벽 disable

- swap off 

- /etc/kubernetes/admin.conf 파일을 리눅스 유저 home에 두고 bashrc에 환경변수 export

- CNI 플러그인: Weave Net

 

 

cf. docker 20.10.17에서 사용하는 containerd, runC 버전 확인

https://docs.docker.com/engine/release-notes/#201017

 

 

cf. 그 외, 특이사항

- kubeadm init 시, 에러가 발생하여 '/etc/containerd/config.toml' 파일을 삭제함

- worker node join 완료 (단, 해당 문제가 worker node의 join 여부와는 상관없는 듯하다)

 

 


 

2. 원인 유추

1) CrashLoopBackOff의 원인 파악

쿠버네티스 구성요소들의 상태를 주기적으로 살펴본 결과, 정상적인 Running과 CrashLoopBackOff이 반복적으로 나타났다. 쿠버네티스를 거의 처음 접하는 상황이다 보니, CrashLoopBackOff를 처음 접했고, 말 그대로 "loopback과 충돌 나서 꺼져버렸다"라는 의미로 해석했다. 하지만 googling 결과 CrashLoopBackOff의 원인은 매우 다양해서 kubectl describe나 kubectl log 커맨드로 직접 확인해서 원인을 파악해야 한다고 한다.

 

$ kubectl logs kubeproxy-8gx8g -n kube-system

 

kubectl 커맨드가 정상적으로 수행되는 때를 찾기 힘들어 모든 구성요소의 로그를 확인할 순 없었고 그나마 네트워크오 관련이 많을 거라 추측되는 'kube-proxy'의 로그만을 확인해 본 결과 아래와 같다.

 

- kube-proxy 로그 확인

더보기

root@master:~# kubectl logs kube-proxy-8gx8g -n kube-system
E0826 05:44:17.348105       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:44:18.355273       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:44:20.577157       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:44:25.170763       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:44:43.285999       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": net/http: TLS handshake timeout
E0826 05:45:00.054925       1 node.go:152] Failed to retrieve node info: Get "https://10.100.0.104:6443/api/v1/nodes/master.example.com": dial tcp 10.100.0.104:6443: connect: connection refused
I0826 05:45:00.054948       1 server.go:850] "Can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag"
I0826 05:45:00.054964       1 server_others.go:138] "Detected node IP" address="127.0.0.1"
I0826 05:45:00.054974       1 server_others.go:578] "Unknown proxy mode, assuming iptables proxy" proxyMode=""
I0826 05:45:00.065764       1 server_others.go:206] "Using iptables Proxier"
I0826 05:45:00.065780       1 server_others.go:213] "kube-proxy running in dual-stack mode" ipFamily=IPv4
I0826 05:45:00.065784       1 server_others.go:214] "Creating dualStackProxier for iptables"
I0826 05:45:00.065790       1 server_others.go:501] "Detect-local-mode set to ClusterCIDR, but no IPv6 cluster CIDR defined, , defaulting to no-op detect-local for IPv6"
I0826 05:45:00.065806       1 proxier.go:262] "Setting route_localnet=1, use nodePortAddresses to filter loopback addresses for NodePorts to skip it https://issues.k8s.io/90259"
I0826 05:45:00.065889       1 proxier.go:262] "Setting route_localnet=1, use nodePortAddresses to filter loopback addresses for NodePorts to skip it https://issues.k8s.io/90259"
I0826 05:45:00.066024       1 server.go:661] "Version info" version="v1.25.0"
I0826 05:45:00.066033       1 server.go:663] "Golang settings" GOGC="" GOMAXPROCS="" GOTRACEBACK=""
I0826 05:45:00.066986       1 conntrack.go:52] "Setting nf_conntrack_max" nf_conntrack_max=131072
I0826 05:45:00.067319       1 config.go:317] "Starting service config controller"
I0826 05:45:00.067331       1 shared_informer.go:255] Waiting for caches to sync for service config
I0826 05:45:00.067341       1 config.go:226] "Starting endpoint slice config controller"
I0826 05:45:00.067342       1 shared_informer.go:255] Waiting for caches to sync for endpoint slice config
I0826 05:45:00.067688       1 config.go:444] "Starting node config controller"
I0826 05:45:00.067702       1 shared_informer.go:255] Waiting for caches to sync for node config
E0826 05:45:00.067991       1 event_broadcaster.go:262] Unable to write event: 'Post "https://10.100.0.104:6443/apis/events.k8s.io/v1/namespaces/default/events": dial tcp 10.100.0.104:6443: connect: connection refused' (may retry after sleeping)
W0826 05:45:00.068027       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:00.068047       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Node: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:00.068070       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:00.068111       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Service: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:00.068136       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:00.068175       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:01.088297       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:01.088361       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:01.290468       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:01.290603       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Service: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:01.424499       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:01.424641       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Node: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:02.752168       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:02.752188       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:03.329487       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:03.329551       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Node: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:03.661785       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:03.661812       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Service: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:07.646986       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:07.647122       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:07.879699       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:07.879876       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Service: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:09.058316       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:09.058467       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Node: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:10.917765       1 event_broadcaster.go:262] Unable to write event: 'Post "https://10.100.0.104:6443/apis/events.k8s.io/v1/namespaces/default/events": dial tcp 10.100.0.104:6443: connect: connection refused' (may retry after sleeping)
W0826 05:45:15.395682       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:15.395718       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://10.100.0.104:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:16.955647       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:16.955708       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Node: failed to list *v1.Node: Get "https://10.100.0.104:6443/api/v1/nodes?fieldSelector=metadata.name%3Dmaster.example.com&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
W0826 05:45:19.116403       1 reflector.go:424] vendor/k8s.io/client-go/informers/factory.go:134: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:19.116897       1 reflector.go:140] vendor/k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.Service: failed to list *v1.Service: Get "https://10.100.0.104:6443/api/v1/services?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0": dial tcp 10.100.0.104:6443: connect: connection refused
E0826 05:45:22.635201       1 event_broadcaster.go:262] Unable to write event: 'Post "https://10.100.0.104:6443/apis/events.k8s.io/v1/namespaces/default/events": dial tcp 10.100.0.104:6443: connect: connection refused' (may retry after sleeping)

 

 

2) 호스트 IP와 루프백 IP(localhost)가 서로 충돌 난 것

로그 파일 분석

"Can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag"

localhost IP인 127.0.0.1을 시도했으나 해당 IP가 정확하지 않다는 메시지이다. 따라서 호스트 IP와 loopback IP인 localhost가 서로 충돌이 났을 거란 추측을 시작했다.

 

하지만 API 서버의 설정 파일인 '/etc/kubernetes/manifests/kube-apiserver.yaml' 파일 확인 결과 10.100.0.104로 설정되어 있음을 확인했으며, 또한 '/etc/kubernetes/admin.conf' 파일에서 localhost나 127.0.0.1, 또는 master.example.com(master 노드의 hostname)으로 변경해도 문제는 해결되지 않았다. 즉, IP 충돌로 인한 문제는 아니다.

 

 

3) proxy-mode 설정 문제?

위 로그 중 일부는 아래와 같다.

 

I0826 05:45:00.054974       1 server_others.go:578] "Unknown proxy mode, assuming iptables proxy" proxyMode=""
I0826 05:45:00.065764       1 server_others.go:206] "Using iptables Proxier"
I0826 05:45:00.065780       1 server_others.go:213] "kube-proxy running in dual-stack mode" ipFamily=IPv4
I0826 05:45:00.065784       1 server_others.go:214] "Creating dualStackProxier for iptables"
I0826 05:45:00.065790       1 server_others.go:501] "Detect-local-mode set to ClusterCIDR, but no IPv6 cluster CIDR defined, , defaulting to no-op detect-local for IPv6"

 

로그를 요약해보면 iptable의 proxy-mode를 확인하던 중에 proxy mode가 ""로 설정되어 알 수 없다는 안내를 한다. 그래서 iptable을 Proxier라는 것으로 설정한다. 하지만 kube-proxy는 dual-stack mode(IPv4와 IPv6를 모두 사용하는 모드)로 실행 중이기 때문에 iptable에 다시 dualStackProxire라는 걸 생성한다. 문제는 그다음에 나오는데, 클러스터의 CIDR이 IPv6에 맞춰져 있지 않기 때문에 IPv6에 대한 설정이 없는 mode로 변경하라는 것 같다.

 

아직 쿠버네티스를 입문한 지 오래되지 않아 해당 에러에 대해서는 정확하게 알 수 없으나, 현재 문제 상황이 kubectl 커맨드가 아예 실행되지 않는 것이 아니라 약 3~5분 간격으로 문제가 생기는 것이기 때문에 정확한 원인으로 삼기 어렵다. 만약 IP를 어떤 것으로(v6, v4)사용할 지 몰라서 발생한 문제라면 kubectl 커맨드가 전혀 실행이 되면 안 될 거라 생각한다.

 

 

4) OOM 킬러에 의해 쿠버네티스 구성요소가 죽은 것

쿠버네티스 구성요소 Pod에 할당된 메모리가 너무 적어 메모리를 초과하여 OOM 킬러가 발동했을 거란 추측을 시작했다. 하지만 로그 확인 결과 OOM이나 memory 관련 에러는 확인할 수 없었다.

 

 

 

5) kubeadm init 옵션 설정 문제? (CORS)

kubeadm init 커맨드를 통해 쿠버네티스를 설치할 때, 다양한 옵션이 존재한다. 처음에는 옵션을 아무런 것도 지정하지 않아서 API 서버로 가는 요청에 CORS 에러가 발생하여 Connection이 Refused되었을 거라 추측했다. 쿠버네티스 API 서버의 CORS에 대해서는 더 알아볼 필요가 있지만 kubeadm init 커맨드는 정상적으로 수행되었기 때문에 원인에서 배제했다.

 

 

 

6) 컨테이너 런타임 호환 문제(feat. k8s 도커 지원 중단)

같은 문제를 겪는 사람들을 찾을 수 있었다. 아래 링크 참고

 

1) 쿠버네티스 API 서버가 지속적으로 죽었다 살아나는 문제에 대한 링크

-> https://stackoverflow.com/q/65669944/19784434 

 

2) 우분투 22.04에서 containerd v1.6.3 이상 버전을 기반으로 설치했을 때 발생하는 문제

-> https://stackoverflow.com/q/72567945/19784434

 

cf. containerd에 대한 포스팅: https://jh-labs.tistory.com/477

 

 

 

위 세 개의 링크에 대한 설명을 정리하면 다음과 같다.

 

https://stackoverflow.com/questions/65669944/kubernetes-api-container-dies-constantly

 

위 커맨트는 stack overflow에서 발췌한 부분이며, 해당 문제는 컨테이너 런타임인 'containerd 버전에 따른 설정 문제'인 것 같다는 의견이다. containerd v1.5.9를 설치하면(현재 docker v20.10.17을 설치했고 여기에는 containerd v1.6.6가 포함됨) 옵션 중에 SystemdCgroup = false가 기본으로 세팅된다. 하지만 이 옵션 설정은 Ubuntu 20.04에서는 정상적으로 동작하지만, Ubuntu 22.04 에서는 정상적으로 동작하지 않는다고 한다. 따라서 Ubuntu 22.04에서는 SystemdCgroup = true로 변경한 뒤 실행하면 정상적으로 동작한다고 한다. 참고로 이러한 문제 때문에 containerd v1.6.2부터는 SystemdCgroup = true가 기본 설정이라고 한다.

 

 

https://stackoverflow.com/questions/72567945/issues-with-stability-with-kubernetes-cluster-before-adding-networking

 

위 사진은 두 번째 stack overflow링크의 핵심 부분을 발췌한 것이다. 요악하면 다음과 같다. Ubuntu "Jammy"(22.04)에서 containerd의 default 설치를 사용했을 경우, containerd의 내장된 default config 파일(/etc/containerd/config.tml)이 비정상적인 설정으로 생성된다고 한다. 심지어 disabled_plugins 설정을 삭제하더라도 containerd 프로세스가 정상적으로 수행되지 않는다고 한다.

 

해당 필자의 추측으로는 containerd에 내장된 defualt 설정이 containerd 프로세스에서 사용되지 않으며 명확하게 어떻게 실행할지를 모르는 것 같다고 한다.

 

링크를 참고해서 containerd를 설치하고 default config 파일을 생성하여 SystemdCgroup을 enable하라고 추천한다.

 


 

해결 방안

1. containerd를 사용하지 말고 대신, CRI-O를 사용해보기 (결국 CRI라는 공통 인터페이스를 사용하기 때문에 문제없을 것)

 

2. Ubuntu 22.04를 20.04로 변경하기

 

3. containerd의 config 파일을 직접 수정하기(SystemdCgroup = ture)

- ubuntu 22.04를 그대로 쓰면서 kubernetes와 containerd 버전을 수정하는 방안

 

-> 가장 간단하게 해결할 수 있는 3번 해결책을 적용했다.

 

cf. containerd 쿠버네티스 권장 버전

https://containerd.io/releases/#kubernetes-support

 

안정적인 설치를 하기 위해 릴리즈 된 지 약 1년이 넘은 kubernetes 1.22와 containerd 1.5.5, runC 1.1.1을 선택해서 재설치했다. 특히, 쿠버네티스 v1.20부터 docker는 deprecated되었으며 v1.22부터는 완전히 docker 지원을 중단하고 컨테이너 런타임 인터페이스(CRI) 요구사항을 만족하는 런타임을 사용하도록 바뀌었다. 또한 시스템을 경량으로 가져가기 위해 docker는 설치하지 않았다.

 

containerd, runC 설치 방법: https://jh-labs.tistory.com/484

 

설치 과정 중에 kubeadm init 커맨드에서 아래와 같이 에러가 발생했다.

root@master:~# kubeadm init
I0831 21:06:29.563505    1361 version.go:255] remote version is much newer: v1.25.0; falling back to: stable-1.22
[init] Using Kubernetes version: v1.22.13
[preflight] Running pre-flight checks
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
        [ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

 

네트워크 브릿지가 제대로 설정되지 않은 듯하다. 아래와 같이 를 사용하여 재설정해주었더니 정상적으로 수행되었다.

$ echo '1' > /proc/sys/net/ipv4/ip_forward
$ modprobe br_netfilter
$ echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables

 


 

결과 비교

ubuntu@master:~$ kubectl get nodes -o wide
NAME                 STATUS   ROLES                  AGE     VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
master.example.com   Ready    control-plane,master   2d19h   v1.22.8   10.100.0.104   <none>        Ubuntu 22.04.1 LTS   5.15.0-46-generic   containerd://1.5.5
node1.example.com    Ready    <none>                 2d19h   v1.22.8   10.100.0.101   <none>        Ubuntu 22.04.1 LTS   5.15.0-46-generic   containerd://1.5.5
node2.example.com    Ready    <none>                 2d19h   v1.22.8   10.100.0.102   <none>        Ubuntu 22.04.1 LTS   5.15.0-46-generic   containerd://1.5.5

 

약 2일 동안 kubectl 커맨드가 문제없이 동작했다.

 

worker 노드를 join 시킨 뒤 확인해보니 kube-proxy 3개 CNI(weave-net) 3개가 정상적으로 동작한다.

 

 

 

첫 번째 kube-proxy 로그 확인 결과

$ kubectl logs kube-proxy-6b7gx -n kube-system
I0831 12:47:05.799147       1 server_others.go:140] Detected node IP 10.100.0.104
W0831 12:47:05.799208       1 server_others.go:565] Unknown proxy mode "", assuming iptables proxy
I0831 12:47:05.832699       1 server_others.go:206] kube-proxy running in dual-stack mode, IPv4-primary
I0831 12:47:05.832771       1 server_others.go:212] Using iptables Proxier.
I0831 12:47:05.832788       1 server_others.go:219] creating dualStackProxier for iptables.
W0831 12:47:05.833115       1 server_others.go:479] detect-local-mode set to ClusterCIDR, but no cluster CIDR defined
W0831 12:47:05.833144       1 server_others.go:528] detect-local-mode: ClusterCIDR , defaulting to no-op detect-local

IP 10.100.0.104에 대한 kube-proxy 이므로 master의 kube-proxy이다. (위 부분은 2, 3번째 kube-proxy 로그에서도 공통으로 등장함)

 

 

문제가 발생했을 때의 로그와 차이점을 보면 아래와 같다.

## 문제 발생시 kube-proxy 로그
"Can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag"
Detected node IP" address="127.0.0.1"

"Unknown proxy mode, assuming iptables proxy" proxyMode=""

-------------------------------------------------------------

## 현재 kube-proxy 로그
Successfully retrieved node IP: 10.100.0.102
Detected node IP 10.100.0.102

Unknown proxy mode "", assuming iptables proxy
kube-proxy running in dual-stack mode, IPv4-primary

'net/netfilter/nf_conntrack_tcp_timeout_established' to 86400

버전에 따른 차이는 있겠지만 문제 발생 시에는 kube-proxy가 프록시 모드를 제대로 설정하지 못했으며 그래서 IP도 제대로 파악하지 못했던 것 같다. 현재 로그와 비교해보면 지금은 iptable의 프록시 모드를 IPv4를 우선시하도록 설정했다는 차이가 있는 것 같다.

 

고수준 컨테이너 런타임(High-Level Container Runtime)의 역할 중 하나가 컨테이너들(쿠버네티스 구성요소)의 네트워크를 설정해서 runC로 명령을 하달하는 것인데, 아마 이 부분에서 문제가 있었던 것 같다. 

 

정리

각 컨테이너가 사용할 CPU, 메모리, 네트워크 자원을 제한하는 리눅스의 cgroup(control group) 설정이 containerd에 제대로 적용되지 않아서 발생했던 문제였고, 결국 containerd 설정 파일(/etc/containerd/config.toml)에서 SystemdCgroup을 true로 설정하여 runC가 cgroup 드라이버를 사용하도록 하여 해결되었다.

 

containerd의 SystemdCgroup = true 설정은 cgroup 드라이버로 systemd를 사용하겠다는 의미이다. cgroup 드라이버의 종류는 아래와 같이 2개가 있다.

 

1) cgroupfs

2) systemd

 

kubelet과 컨테이너 런타임이 '동일한' cgroup 드라이버를 사용하고 동일하게 구성하는 것이 중요하다고 한다. (https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cgroup-drivers) 또한 cgroupfs드라이버는 kubelet의 기본 cgroup 드라이버이다 . 드라이버를 사용할 때 cgroupfs kubelet과 컨테이너 런타임은 cgroup 파일 시스템과 직접 인터페이스하여 cgroup을 구성한다. systemd가 시스템에서 단일 cgroup 관리자를 예상하기 때문에 systemd 가 초기화 시스템인 경우 cgroupfs드라이버는 권장 되지 않는다고 한다.

 

 

 

cf. 현재 kube-proxy 전체 로그

더보기

root@master:~# kubectl logs kube-proxy-6b7gx -n kube-system
I0831 12:47:05.799067       1 node.go:172] Successfully retrieved node IP: 10.100.0.104
I0831 12:47:05.799147       1 server_others.go:140] Detected node IP 10.100.0.104
W0831 12:47:05.799208       1 server_others.go:565] Unknown proxy mode "", assuming iptables proxy
I0831 12:47:05.832699       1 server_others.go:206] kube-proxy running in dual-stack mode, IPv4-primary
I0831 12:47:05.832771       1 server_others.go:212] Using iptables Proxier.
I0831 12:47:05.832788       1 server_others.go:219] creating dualStackProxier for iptables.
W0831 12:47:05.833115       1 server_others.go:479] detect-local-mode set to ClusterCIDR, but no cluster CIDR defined
W0831 12:47:05.833144       1 server_others.go:528] detect-local-mode: ClusterCIDR , defaulting to no-op detect-local
I0831 12:47:05.834154       1 server.go:649] Version: v1.22.13
I0831 12:47:05.835485       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_max' to 131072
I0831 12:47:05.835544       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0831 12:47:05.835608       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_established' to 86400
I0831 12:47:05.835690       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_close_wait' to 3600
I0831 12:47:05.838462       1 config.go:315] Starting service config controller
I0831 12:47:05.838514       1 shared_informer.go:240] Waiting for caches to sync for service config
I0831 12:47:05.838571       1 config.go:224] Starting endpoint slice config controller
I0831 12:47:05.838588       1 shared_informer.go:240] Waiting for caches to sync for endpoint slice config
I0831 12:47:05.940666       1 shared_informer.go:247] Caches are synced for endpoint slice config
I0831 12:47:05.940696       1 shared_informer.go:247] Caches are synced for service config

 

 

** 결론: Ubuntu 22.04에서 발생하는 컨테이너 런타임(containerd) 설정 문제

 

 

 

Reference

- containerd, OCI 표준이란, https://jh-labs.tistory.com/477

- 쿠버네티스 도커 지원 중단, https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/

- 쿠버네티스 API 서버가 지속적으로 죽었다 살아나는 문제, https://stackoverflow.com/q/65669944/19784434 

- 우분투와 containerd 버전에 대한 문제,https://stackoverflow.com/q/72567945/19784434

- 쿠버네티스 도커에서 containerd로, https://tech.osci.kr/2021/10/28/%eb%9f%b0%ed%83%80%ec%9e%84-docker%ec%97%90%ec%84%9c-containerd%eb%a1%9c/

- 우분투 22.04에 containerd 설치하기, https://www.itzgeek.com/how-tos/linux/ubuntu-how-tos/install-containerd-on-ubuntu-22-04.html

- Kubernetes Architecture, https://ssup2.github.io/theory_analysis/Kubernetes_Architecture/

- cgroupfs driver, https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cgroupfs-cgroup-driver

- systemd cgroup driver, https://kubernetes.io/docs/setup/production-environment/container-runtimes/#systemd-cgroup-driver

- cgroup driver in kubernetes, https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cgroup-drivers

 

 

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함