Kubernetes 클러스터 안에서 문제 조사하기
Apollo는 Kubernetes와 Helm API로 리소스를 변경하고, 여러 클러스터의 운영 정보를 허브에 모읍니다. Pod의 시작 실패나 애플리케이션 오류를 조사할 때는 클러스터 안의 도구도 사용해야 합니다.
특히 Pod의 애플리케이션 로그는 Apollo에 표시되지 않습니다. Apollo가 표시하는 Helm과 Kubernetes의 정보에 더해, 조직에서 사용하는 로그 조회 수단이나 kubectl logs로 애플리케이션 로그를 확인해야 합니다.
명령을 실행할 클러스터에 접근할 수 있어야 하며, 조사할 리소스와 로그를 읽을 권한이 필요합니다. 이하의 이름, 주소와 출력은 WordPress를 설치한 가상의 환경을 설명하기 위한 예시입니다. 명령의 Pod 이름과 네임스페이스는 실제 대상에 맞추어 바꿉니다.
Pod 상태 확인
모든 네임스페이스의 Pod를 조회합니다.
kubectl get pods --all-namespaces
다음은 출력 예시입니다.
NAMESPACE NAME READY STATUS RESTARTS AGE
default wordpress-57577c7cf9-99b8t 1/1 Running 0 3h33m
default wordpress-mariadb-0 1/1 Running 0 3h33m
infrastructure-test expected-state-k8s-69ccbc7b47-qw9s7 1/1 Running 0 7h20m
infrastructure-test expected-state-k8s-69ccbc7b47-rsjwd 1/1 Running 0 7h20m
infrastructure-test helm-chart-operator-6986d7cff7-xtb94 1/1 Running 0 7h20m
kube-system coredns-6d4b75cb6d-kx5c9 1/1 Running 0 7h29m
kube-system kube-scheduler-kind-control-plane3 1/1 Running 1 7h26m
local-path-storage local-path-provisioner-9cd9bd544-qtth4 1/1 Running 0 7h29m
NAMESPACE와 NAME은 후속 조회 명령에서 대상을 지정할 때 사용합니다. 애플리케이션 Pod뿐 아니라 helm-chart-operator, expected-state-k8s 같은 Apollo 구성 요소의 상태도 확인할 수 있습니다.
시작 실패의 이벤트 확인
Pod가 Pending, CreateContainerConfigError, ImagePullBackOff 상태라면 kubectl describe pod의 마지막에 있는 Events를 확인합니다.
kubectl describe pod wordpress-584d8d7dbf-gflrl --namespace default
상세 정보에는 Pod가 배치된 노드, 시작 시각, 서비스 계정, 레이블과 어노테이션 등이 포함됩니다. Apollo가 관리하는 리소스에서는 배포 개체와 배포 환경, 제품을 연결할 메타데이터도 찾을 수 있습니다.
| 정보 | 예시 |
|---|---|
| 배포 개체 ID 어노테이션 | apollo.palantir.com/metadata.entity.id: aeid:troubleshoot-3x5x:helm-chart:wordpress |
| 배포 환경 ID 어노테이션 | apollo.palantir.com/metadata.environment.id: troubleshoot-3x5x |
| 제품 그룹 어노테이션 | apollo.palantir.com/metadata.product.group: com.example |
| 제품 이름 어노테이션 | apollo.palantir.com/metadata.product.name: wordpress |
| 제품 버전 어노테이션 | apollo.palantir.com/metadata.product.version: 18.1.0 |
| 애플리케이션 버전 레이블 | app.kubernetes.io/version=6.3.2 |
| Helm 차트 레이블 | helm.sh/chart=wordpress-18.1.0 |
차트 버전은 18.1.0이고 컨테이너 안에서 실행되는 애플리케이션 버전은 6.3.2입니다. 두 버전은 별도로 관리합니다.
정상적으로 시작되는 Pod의 이벤트에는 다음과 같은 순서가 나타날 수 있습니다.
Type Reason From Message
Normal Scheduled default-scheduler Successfully assigned default/wordpress-584d8d7dbf-gflrl to kind-worker3
Normal Pulling kubelet Pulling image "docker.io/bitnami/wordpress:6.3.2-debian-11-r5"
Normal Pulled kubelet Successfully pulled image "docker.io/bitnami/wordpress:6.3.2-debian-11-r5"
Normal Created kubelet Created container wordpress
Normal Started kubelet Started container wordpress
스케줄링, 이미지 다운로드, 컨테이너 생성과 시작 중 어느 단계까지 진행되었는지와 그 뒤의 오류 메시지를 함께 살펴봅니다.
실행 후 오류의 로그 확인
Pod가 시작했지만 Error나 CrashLoopBackOff 상태라면 애플리케이션 로그를 확인합니다. kubectl get pods에서 찾은 Pod 이름을 사용합니다.
kubectl logs wordpress-584d8d7dbf-gflrl --namespace default --since 1m
--since 1m은 최근 1분의 로그로 범위를 줄입니다. 조사하려는 오류가 발생한 시점에 맞추어 범위를 선택합니다.
WordPress 초기화 로그에는 인증서 생성, HTTP와 HTTPS 포트 설정, PHP 설정, 데이터베이스 환경 변수 확인과 데이터베이스 연결 시도 등이 나타날 수 있습니다. 예를 들어 다음 경고는 운영 환경에서 빈 비밀번호 허용 설정을 사용하지 말라는 의미입니다.
WARN ==> You set the environment variable ALLOW_EMPTY_PASSWORD=yes. For safety reasons, do not use this flag in a production environment.
로그에 Trying to connect to the database server가 반복되거나 파일 경로 오류가 나타나는 경우에는 그 애플리케이션의 설정과 의존 서비스를 조사합니다.
실행 중인 Pod 안에서 더 깊게 조사해야 한다면 컨테이너에 포함된 도구와 접근 방식을 확인해야 합니다. 컨테이너 구성에 따라 사용할 수 있는 조사 수단이 다릅니다.
서비스 주소와 LoadBalancer 확인
Kubernetes Service는 컨테이너로 클러스터 내부 또는 외부 트래픽을 전달합니다. Helm 차트로 배포한 웹사이트의 주소를 찾을 때는 Service를 확인합니다.
kubectl get svc --namespace default
다음은 출력 예시입니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP
wordpress LoadBalancer 10.96.31.110 <pending> 80:32314/TCP,443:32281/TCP
wordpress-mariadb ClusterIP 10.96.200.146 <none> 3306/TCP
이 예시에서 WordPress의 외부 IP는 아직 <pending>입니다. Service가 존재하는 것과 외부에서 사용할 주소가 준비된 것은 다릅니다.
LoadBalancer가 없는 환경
일부 Helm 차트는 배포 환경에 LoadBalancer가 있다고 가정합니다. GKE, AKS와 EKS 같은 클라우드 Kubernetes 환경에서는 클라우드 제공자의 기능으로 Service에 IP 주소를 할당할 수 있습니다.
로컬 kind 클러스터에는 같은 구성이 기본으로 준비되어 있지 않습니다. LoadBalancer를 요구하는 WordPress 같은 차트는 필요한 지원 리소스가 없으면 설치에 실패할 수 있습니다.
Service does not have load balancer ingress IP address: default/wordpress
기본 로컬 kind 환경에서는 MetalLB 같은 LoadBalancer를 추가하는 방식으로 해결할 수 있습니다. 실제 해결 방법은 해당 클러스터의 인프라와 차트 설정에 맞추어 결정해야 합니다.
Kubernetes 학습용 minikube도 기본 사례에는 사용할 수 있지만 Apollo를 함께 사용하는 데 제약이 있을 수 있습니다. Apollo의 로컬 학습과 테스트에는 다중 노드 kind 클러스터 구성이 권장됩니다.
Helm 릴리스 조회
Apollo는 Helm 차트 유형의 배포 개체를 Helm으로 관리합니다. 대상 클러스터에 접근할 수 있으면 일반적인 Helm 조회 명령을 그대로 사용할 수 있습니다.
Helm CLI의 주버전에 따라 전체 상태의 릴리스를 조회하는 옵션은 다릅니다.
| Helm CLI | 현재 네임스페이스의 모든 상태 조회 |
|---|---|
| Helm 3 | helm list --all |
| Helm 4 | helm list |
두 버전 모두 --all-namespaces로 네임스페이스 범위를 넓힐 수 있습니다. Helm 3의 --all은 상태 필터를 해제하는 옵션이며 네임스페이스 범위를 넓히는 옵션이 아닙니다.
조회 결과에는 릴리스 이름, 네임스페이스, 리비전, 갱신 시각, 상태, 차트와 애플리케이션 버전이 표시됩니다. WordPress 릴리스라면 다음과 같은 내용을 확인할 수 있습니다.
NAME NAMESPACE REVISION STATUS CHART APP VERSION
wordpress default 6 deployed wordpress-18.1.0 6.3.2
릴리스 이력
helm history wordpress --namespace default
다음은 같은 차트 버전에서 설치와 업그레이드가 실패한 뒤 롤백이 기록된 가상의 이력입니다.
| 리비전 | 상태 | 설명 |
|---|---|---|
| 1 | failed | 설치 중 조건 충족을 기다리다가 시간 초과 |
| 2 | failed | 업그레이드 중 시간 초과 |
| 3 | failed | 업그레이드 중 시간 초과 |
| 4 | failed | 업그레이드 중 시간 초과 |
| 5 | pending-upgrade | 업그레이드 준비 |
| 6 | deployed | 리비전 4로 롤백 |
현재 상태만 보면 성공한 릴리스처럼 보여도 이전 리비전에서 실패와 롤백이 있었는지 이력으로 확인할 수 있습니다.
실제 전달한 Values
helm get values wordpress --namespace default
이 명령은 해당 릴리스에 전달된 Values를 조회합니다. Apollo의 아티팩트 저장소 URI, 배포 개체 ID, 배포 환경 ID, 제품 그룹과 이름 및 버전 등의 값과 사용자가 지정한 서비스 설정을 확인하는 데 사용할 수 있습니다.
예를 들어 서비스 유형으로 NodePort를 전달했는지, 제품이 com.example 그룹의 wordpress이며 버전이 18.1.0인지 확인할 수 있습니다. helm get values --all은 계산된 전체 값을 포함하므로, 사용자가 전달한 값만 조회하는 기본 명령과 구분합니다.
에이전트 Pod가 실행 중이지만 허브에 보고하지 않는 경우
Apollo 에이전트의 Pod가 Running이어도 허브에 상태를 보고하지 못할 수 있습니다. 이 경우 Apollo가 배포 환경에 변경 계획을 발행하지 못하므로 Pod 상태와 Apollo의 연결 상태를 함께 확인해야 합니다.
로컬 클러스터에서는 초기 매니페스트를 다시 적용하는 방법을 사용할 수 있습니다.
- Apollo에서 배포 환경을 엽니다.
- 오른쪽 위의 Actions → Environment setup instructions를 선택합니다.
- 안내에 따라 매니페스트를 다운로드하고 해당 클러스터에 적용합니다.
- 약 1분 뒤 페이지를 새로 고쳐 에이전트 연결을 확인합니다.
Docker를 종료하거나 다시 시작한 경우, 또는 컴퓨터를 다시 시작한 경우에는 에이전트가 허브에 재연결하지 못할 수 있습니다. 위 절차 후에도 연결되지 않으면 새 배포 환경을 생성하고 클러스터를 연결하는 방법이 필요할 수 있습니다.