일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 기본유형
- Spring
- 자바
- 다시보기
- SWEA
- 그리디
- 알고리즘기본개념
- 백준
- DFS
- SSAFY
- Union Find
- 유니온파인드
- database
- 완전탐색
- 싸피
- 완탐
- JUnit
- 코테
- 다익스트라
- 코딩테스트실력진단
- 그래프
- 코드트리
- 부분수열의합2
- BFS
- 알고리즘
- 트러블슈팅
- DP
- JPA
- Java
- 코딩테스트
- Today
- Total
HwangHub
[K8S] kubeadm init이 안되던 이유 (feat. registry.k8s.io) 본문
상황
- OS: Centos 7.6.1810
- K8S: v1.25.1
- Container Runtime: Docker (Inteface: cri-docker)
운영중인 솔루션이 쿠버네티스 기반으로 동작하고 있었고, 이를 파악하기 위해 솔루션 설치를 수행하던 중 문제가 발생했다.
구체적으로, kubeadm init을 수행했을 때 계속 아래와 같은 메시지가 4분 동안 반복되다가 timeout이 났다.
HTTP Trace: Dial to tcp:192.168.77.232:6443 failed: dial tcp 192.168.77.232:6443: connect: connection refused
GET https://192.168.77.232:6443/healthz?timeout=10s in 0 milliseconds
HTTP Statistics: DNSLookup 0 ms Dial 0 ms TLSHandshake 0 ms Duration 0 ms
Response Headers:
curl -v -XGET -H "Accept: application/json, */*" -H User-Agent: kubeadm/v1.25.1 (linux/amd64) kubernetes/q1w2e2b" 'https://192.168.77.232:6443/healthz?timeout=10s'
직관적으로 kube apiserver가 연결이 되지 않는단 걸 알았고, 원인 파악을 위해 kubelet 로그를 찍어 보았다. 그랬더니 아래 에러가 반복되고 있었다.
# journalctl -xeu kubelet
"Error getting node" err="node "master01" not found"
위 에러는 kubelet이 k8s 클러스터에서 해당 노드를 찾지 못해 않아 발생하는 것으로 보았다. 결국 kubeadm init이 정상적으로 수행되지 못해 발생하는 것이라서, 문제 원인은 다른 곳에 있을 거라 보았다.
무엇이 문제일까 하다 container runtime으로 사용하고 있는 도커의 로그를 확인해봤다.
# journalctl -xeu docker
level=warning ms"Error getting v2 registry: Get "https://k8s.gcr.io/v2/": dial tcp: lookup k8s.gcr.io on 192.168.77.124:53: server misbehaving"
어라?
왜 k8s.gcr.io를 dns lookup 하고 있지? (53번 포트는 dns 질의 포트; udp / tcp 둘다 가능)
k8s.gcr.io는 과거에 쿠버네티스 control-plane component 들의 이미지를 저장하던 레포지토리 주소다. 문제는 2023년 2월 6일, 쿠버네티스 프로젝트에서 공식적으로 k8s.gcr.io 레지스트리에 대한 지원을 중단했다는 거다. (이는 쿠버네티스 프로젝트가 보다 지속 가능한 인프라 모델을 채택하기 위한 조치였으며, 기존의 Google Cloud Registry(gcr.io) 의존성에서 벗어나 커뮤니티가 소유한 registry.k8s.io로 전환하는 것이 목적이었다.)
참고: https://kubernetes.io/blog/2023/02/06/k8s-gcr-io-freeze-announcement/
현재는 k8s.gcr.io 업데이트를 완전 중단한 상태이고, 나 또한 k8s.gcr.io가 아니라 registry.k8s.io로 이미지 레지스트리 주소를 모두 변경한 상태이다.
참고로, kubeadm config images list 를 입력하면 아래와 같이 뜬다. 즉, k8s에선 이미 관련 조치가 되어있는 것을 알 수 있다.
# kubeadm config images list
registry.k8s.io/coredns/coredns:v1.9.3
registry.k8s.io/etcd:3.5.4-0
registry.k8s.io/kube-apiserver:v1.25.1
registry.k8s.io/kube-controller-manager:v1.25.1
registry.k8s.io/kube-proxy:v1.25.1
registry.k8s.io/kube-scheduler:v1.25.1
registry.k8s.io/pause:3.8
지금까지의 단서를 바탕으로 상황을 정리하자면 이렇다.
- kubeadm init 과정에서 누군가가 registry.k8s.io 가 아닌 k8s.gcr.io 이미지를 사용하려는 상황이다.
- imagePullPolicy가 IfNotExist이므로 로컬에 해당 이미지가 없으면 이미지를 해당 레지스트리에서 pull 하려고 시도할 것이다.
- 해당 레지스트리 도메인에 대한 ip 주소가 host파일에 명시되어 있지 않으니 dns query를 수행하려고 할 것이다.
- (내가 작업하는 환경이 폐쇄망이라) dns query를 통해 k8s.gcr.io 레지스트리 서버를 찾을 수 없어 lookup이 timout된다.
- 레지스트리와 연결될 수 없으니 필요한 도커 이미지를 로딩하지 못해 과정 가운데 에러가 발생하여 node를 등록할 수 없다.
그렇다면 kubeadm이 아니라 다른 프로세스가 k8s.gcr.io 이미지를 호출하고 있다는 이야기가 된다. 그 다음으로 kubeadm init 과정에서 주로 사용될만한 프로세스는 cri-docker였다. 실제로, pod의 인프라 컨테이너로 pause 컨테이너를 띄울 때 kubeadm 과 별개로 cri-docker가 갖고 있는 pause 이미지 값이 존재했다. 즉, cri-docker가 k8s.gcr.io/pause 이미지를 필요로 하는 것으로 파악했다.
참고1: https://kubernetes.io/docs/setup/production-environment/container-runtimes/
참고2: https://github.com/kubernetes/kubeadm/issues/2801
따라서 해결책은 두 가지가 있을 것이다.
- --pod-infra-container-image 옵션을 활용하여 cri-docker가 사용하는 pause 이미지를 지정한다.
- 현재 cri-docker가 사용하는 k8s.gcr.io 레지스트리 도커 이미지를 로컬에 설치하여 활용한다.
합리적으로 판단하기엔 --pod-infra-container-image 옵션을 활용하여 registry.k8s.io/pause 이미지를 지정하고 활용하는 게 더 나은 방향이라고 (개인적으론) 생각한다. 왜냐하면 공식적으로 쿠버네티스 프로젝트에서 k8s.gcr.io 레지스트리에 대한 지원이 완전 중단되었고, 그 시기가 꽤 오래 돼었으니 말이다.
하지만 업무 환경의 특수성 또한 고려하지 않을 수 없다. 우리는 외부 인터넷망을 통해 image가 활용되도록 솔루션을 운영하지 않고, 수동으로 docker image를 반입하여 로컬에 설치하여 운영한다. 즉 쿠버네티스 프로젝트에서 해당 레지스트리를 지원하지 않고 있다는 사실은 현재 운영 환경의 특수성을 고려할 때 큰 영향도가 있지 않았다. (필요하면 registry.k8s.io 에서 수동으로 받아오면 되니까)
따라서 이미 운영 환경에서 같이 사용하고 있던 pause 이미지를 활용하여 유지하는 것으로 방향성을 설정하였다. 이는 지금까지의 운영 히스토리 방향성을 따르기 때문에 리스크가 적으며, 레지스트리 값을 변경하는 것으로 얻는 효과가 미미한데, 변경을 위해 들어가는 비용은 크기 때문이었다. 결정을 마무리한 뒤, k8s.gcr.io/pause:3.6 docker images 파일을 추가해주고 다시 kubeadm init 을 수행하니 예상대로 정상적으로 잘 수행되었다.
정리하고 보니 단순한 문제였는데, 원인을 찾는 것 부터 결론을 짓기까지 2일이라는 시간을 거의 통째로 썼다. 처음 디버깅의 미궁에 빠질 떄에는 캄캄하고 난감한데, 알고난 뒤에 느껴지는 편안함은 언제나 행복감을 준다.
'workspace > 아티클' 카테고리의 다른 글
[트러블슈팅] The project you were looking for could not be found or you don't have permission to view it. (@git의 권한 체크) (1) | 2024.03.22 |
---|---|
[개선] 백만 단위 데이터 처리를 위한 커버링 인덱스 도입 (속도 184배 향상) (1) | 2024.03.18 |
[트러블슈팅] 로그인 구현시 Authorization 헤더가 프론트의 response header에 확인되지 않는 현상 (0) | 2024.02.10 |
Spring MVC - 서블릿 (1) | 2024.02.06 |
웹 통신을 위한 네트워크 이해하기 3 - QUIC (UDP) (0) | 2024.02.04 |