Skip to content

Commit 81e282e

Browse files
kiku99claude
andcommitted
content: add kubernetes problems 024-033
- 024: Init Container 완료 불가 (난이도 1) - 025: 사이드카 컨테이너 크래시 (난이도 2) - 026: 롤링 업데이트 실패 롤백 (난이도 1) - 027: HPA 메트릭 부재 스케일링 불가 (난이도 2) - 028: Service selector 불일치 (난이도 1) - 029: Ingress path 라우팅 오류 (난이도 2) - 030: Volume 권한 오류 (난이도 2) - 031: runAsNonRoot 정책 위반 (난이도 2) - 032: nodeAffinity 라벨 불일치 (난이도 2) - 033: Taint toleration 불일치 (난이도 2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c1165c9 commit 81e282e

10 files changed

Lines changed: 973 additions & 0 deletions
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
id: "kubernetes-024"
3+
title: "Init Container가 완료되지 않아 Pod가 시작되지 않는 문제"
4+
category: "kubernetes"
5+
difficulty: 1
6+
tags: ["init-container", "pending", "pod", "debugging"]
7+
hints:
8+
- "kubectl describe pod 출력에서 Init Containers 섹션의 State를 확인하세요."
9+
- "Init Container의 로그를 확인해 어떤 명령이 실행 중인지 살펴보세요."
10+
- "Init Container가 대기하는 대상 서비스가 실제로 존재하는지 확인하세요."
11+
---
12+
13+
## 상황
14+
15+
신규 마이크로서비스를 배포했는데 Pod가 `Init:0/1` 상태에서 멈춰 있습니다. 메인 컨테이너가 시작되지 않아 서비스 전체가 동작하지 않습니다. 제공된 정보를 분석하여 원인을 찾으세요.
16+
17+
## 데이터
18+
19+
### kubectl get pods 출력
20+
21+
```bash
22+
NAME READY STATUS RESTARTS AGE
23+
order-service-5c8d7f9b6-tn4k2 0/1 Init:0/1 0 8m
24+
order-service-5c8d7f9b6-gx7m3 0/1 Init:0/1 0 8m
25+
```
26+
27+
### kubectl describe pod order-service-5c8d7f9b6-tn4k2 (발췌)
28+
29+
```yaml
30+
Init Containers:
31+
wait-for-db:
32+
Image: busybox:1.36
33+
Command:
34+
- sh
35+
- -c
36+
- until nslookup postgres-primary.database.svc.cluster.local; do echo "Waiting for DB..."; sleep 2; done
37+
State: Running
38+
Started: Mon, 20 Jan 2025 09:10:00 +0000
39+
Ready: False
40+
Containers:
41+
order-api:
42+
Image: registry.example.com/order-service:v3.0.1
43+
State: Waiting
44+
Reason: PodInitializing
45+
Events:
46+
Type Reason Age From Message
47+
---- ------ ---- ---- -------
48+
Normal Scheduled 8m default-scheduler Successfully assigned default/order-service-5c8d7f9b6-tn4k2
49+
Normal Pulled 8m kubelet Container image "busybox:1.36" already present on machine
50+
Normal Created 8m kubelet Created container wait-for-db
51+
Normal Started 8m kubelet Started container wait-for-db
52+
```
53+
54+
### kubectl logs order-service-5c8d7f9b6-tn4k2 -c wait-for-db (최근 출력)
55+
56+
```log
57+
Server: 10.96.0.10
58+
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
59+
60+
nslookup: can't resolve 'postgres-primary.database.svc.cluster.local'
61+
Waiting for DB...
62+
nslookup: can't resolve 'postgres-primary.database.svc.cluster.local'
63+
Waiting for DB...
64+
nslookup: can't resolve 'postgres-primary.database.svc.cluster.local'
65+
Waiting for DB...
66+
```
67+
68+
### kubectl get svc -n database 출력
69+
70+
```bash
71+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
72+
postgres-main ClusterIP 10.96.45.120 <none> 5432/TCP 30d
73+
```
74+
75+
## 해설
76+
77+
### 원인 분석
78+
79+
Init Container `wait-for-db``postgres-primary.database.svc.cluster.local` DNS가 해석될 때까지 무한 대기하도록 설정되어 있습니다. 그러나 `database` 네임스페이스의 실제 Service 이름은 `postgres-main`이지 `postgres-primary`가 아닙니다.
80+
81+
Init Container가 존재하지 않는 Service를 찾고 있어 DNS 조회가 계속 실패하고, Init Container가 영원히 완료되지 않으므로 메인 컨테이너도 시작되지 않습니다.
82+
83+
### 해결 방법
84+
85+
```bash
86+
# 1. database 네임스페이스의 실제 Service 이름 확인
87+
kubectl get svc -n database
88+
89+
# 2. Deployment의 Init Container 명령을 올바른 서비스 이름으로 수정
90+
kubectl edit deployment order-service
91+
# Init Container의 nslookup 대상을 수정:
92+
# postgres-primary.database.svc.cluster.local
93+
# → postgres-main.database.svc.cluster.local
94+
95+
# 3. 롤아웃 상태 확인
96+
kubectl rollout status deployment order-service
97+
98+
# 4. Pod가 정상 Running인지 확인
99+
kubectl get pods
100+
```
101+
102+
### 실무 팁
103+
104+
Init Container로 의존 서비스 대기 패턴을 구현할 때는, 서비스 이름을 하드코딩하지 말고 환경 변수나 ConfigMap으로 관리하세요. 또한 무한 대기 대신 타임아웃을 설정하면(`timeout 120 sh -c 'until ...'`) Init Container가 영원히 멈추는 것을 방지할 수 있습니다.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
id: "kubernetes-025"
3+
title: "사이드카 컨테이너 크래시로 Pod 전체가 불안정한 문제"
4+
category: "kubernetes"
5+
difficulty: 2
6+
tags: ["sidecar", "multi-container", "crashloopbackoff", "logs"]
7+
hints:
8+
- "Pod 안에 컨테이너가 여러 개일 때 kubectl logs -c 옵션으로 특정 컨테이너 로그를 확인하세요."
9+
- "사이드카 컨테이너의 마운트 경로와 메인 컨테이너의 로그 경로가 일치하는지 확인하세요."
10+
- "사이드카가 참조하는 볼륨이 Pod 스펙에 정의되어 있는지 살펴보세요."
11+
---
12+
13+
## 상황
14+
15+
로그 수집을 위해 Fluentd 사이드카를 추가한 뒤 Pod가 반복적으로 재시작됩니다. 메인 애플리케이션 컨테이너는 정상이지만 사이드카 컨테이너가 CrashLoopBackOff 상태입니다. 제공된 정보를 분석하여 원인을 찾으세요.
16+
17+
## 데이터
18+
19+
### kubectl get pods 출력
20+
21+
```bash
22+
NAME READY STATUS RESTARTS AGE
23+
web-app-6f9d8c4b7-r2p5k 1/2 CrashLoopBackOff 4 (18s ago) 3m
24+
```
25+
26+
### kubectl describe pod web-app-6f9d8c4b7-r2p5k (발췌)
27+
28+
```yaml
29+
Containers:
30+
app:
31+
Image: nginx:1.25
32+
State: Running
33+
Ready: True
34+
Mounts:
35+
/var/log/nginx from app-logs (rw)
36+
log-collector:
37+
Image: fluent/fluentd:v1.16
38+
State: Waiting
39+
Reason: CrashLoopBackOff
40+
Last State: Terminated
41+
Reason: Error
42+
Exit Code: 1
43+
Mounts:
44+
/var/log/app from nginx-logs (ro)
45+
Volumes:
46+
app-logs:
47+
Type: EmptyDir
48+
Events:
49+
Warning BackOff 12s (x8 over 2m40s) kubelet Back-off restarting failed container log-collector
50+
```
51+
52+
### kubectl logs web-app-6f9d8c4b7-r2p5k -c log-collector
53+
54+
```log
55+
2025-01-20 09:15:01 +0000 [info]: init supervisor logger path=nil rotate_age=nil rotate_size=nil
56+
2025-01-20 09:15:01 +0000 [info]: parsing config file is succeeded path="/fluentd/etc/fluent.conf"
57+
2025-01-20 09:15:01 +0000 [error]: config error file="/fluentd/etc/fluent.conf" error_class=Errno::ENOENT error="No such file or directory @ rb_sysopen - /var/log/app/access.log"
58+
2025-01-20 09:15:01 +0000 [error]: Worker 0 finished with error. Shutting down.
59+
```
60+
61+
## 해설
62+
63+
### 원인 분석
64+
65+
두 가지 문제가 동시에 발생하고 있습니다.
66+
67+
1. **볼륨 이름 불일치**: 메인 컨테이너 `app`은 `app-logs` 볼륨을 `/var/log/nginx`에 마운트하고 있지만, 사이드카 `log-collector`는 `nginx-logs`라는 **존재하지 않는 볼륨**을 마운트하려 합니다. Pod 스펙의 Volumes에는 `app-logs`만 정의되어 있습니다.
68+
69+
2. **경로 불일치**: 메인 컨테이너는 `/var/log/nginx`에 로그를 쓰고, 사이드카는 `/var/log/app`에서 읽으려 합니다. 같은 볼륨을 공유하더라도 경로가 달라 파일을 찾지 못합니다.
70+
71+
결과적으로 사이드카가 로그 파일을 찾지 못해 시작 직후 크래시합니다.
72+
73+
### 해결 방법
74+
75+
```bash
76+
# 1. Deployment 수정
77+
kubectl edit deployment web-app
78+
79+
# 사이드카의 볼륨 마운트를 수정:
80+
# - 볼륨 이름: nginx-logs → app-logs (실제 존재하는 볼륨)
81+
# - 마운트 경로: /var/log/app → /var/log/nginx (메인 컨테이너와 동일)
82+
83+
# 수정 후 사이드카 컨테이너 스펙:
84+
# volumeMounts:
85+
# - name: app-logs # 올바른 볼륨 이름
86+
# mountPath: /var/log/nginx # 메인 컨테이너와 동일한 경로
87+
# readOnly: true
88+
89+
# 2. Fluentd 설정도 경로에 맞게 확인
90+
# fluent.conf의 path가 /var/log/nginx/access.log를 가리키도록 수정
91+
92+
# 3. 롤아웃 확인
93+
kubectl rollout status deployment web-app
94+
kubectl get pods
95+
```
96+
97+
### 실무 팁
98+
99+
멀티 컨테이너 Pod에서 볼륨을 공유할 때는 모든 컨테이너가 **동일한 볼륨 이름**을 참조하는지 반드시 확인하세요. 또한 Fluentd 같은 로그 수집기 사이드카는 경로가 없을 때 즉시 종료하지 않도록 `read_from_head true`와 `follow_inodes true` 옵션을 설정하는 것이 안정적입니다.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
id: "kubernetes-026"
3+
title: "잘못된 이미지 배포 후 롤링 업데이트 실패 복구"
4+
category: "kubernetes"
5+
difficulty: 1
6+
tags: ["deployment", "rollback", "rollout", "image", "rolling-update"]
7+
hints:
8+
- "kubectl rollout status 명령으로 현재 롤아웃 상태를 확인하세요."
9+
- "kubectl rollout history로 이전 배포 이력을 확인할 수 있습니다."
10+
- "정상이었던 이전 revision으로 롤백하는 방법을 찾아보세요."
11+
---
12+
13+
## 상황
14+
15+
프로덕션 환경에서 API 서버 이미지를 `v2.4.0`에서 `v2.5.0`으로 업데이트했는데, 새 Pod들이 모두 ImagePullBackOff 상태입니다. 기존 v2.4.0 Pod는 아직 살아 있지만 점차 교체되고 있어 빠른 조치가 필요합니다. 제공된 정보를 분석하여 상황을 파악하세요.
16+
17+
## 데이터
18+
19+
### kubectl get pods -l app=api-server 출력
20+
21+
```bash
22+
NAME READY STATUS RESTARTS AGE
23+
api-server-7b8c9d6f5-h4k2n 1/1 Running 0 2d
24+
api-server-7b8c9d6f5-j9m3p 1/1 Running 0 2d
25+
api-server-5a3f8e7d2-w2x4q 0/1 ImagePullBackOff 0 4m
26+
api-server-5a3f8e7d2-v6y8r 0/1 ImagePullBackOff 0 4m
27+
```
28+
29+
### kubectl rollout status deployment/api-server 출력
30+
31+
```log
32+
Waiting for deployment "api-server" rollout to finish: 2 old replicas are pending termination...
33+
```
34+
35+
### kubectl rollout history deployment/api-server 출력
36+
37+
```bash
38+
REVISION CHANGE-CAUSE
39+
1 initial deployment v2.3.0
40+
2 image update to v2.4.0
41+
3 image update to v2.5.0
42+
```
43+
44+
### kubectl describe pod api-server-5a3f8e7d2-w2x4q (Events 발췌)
45+
46+
```log
47+
Events:
48+
Type Reason Age From Message
49+
---- ------ ---- ---- -------
50+
Normal Scheduled 4m default-scheduler Successfully assigned production/api-server-5a3f8e7d2-w2x4q
51+
Normal Pulling 2m (x3 over 4m) kubelet Pulling image "registry.example.com/api-server:v2.5.O"
52+
Warning Failed 2m (x3 over 4m) kubelet Failed to pull image "registry.example.com/api-server:v2.5.O": tag does not exist
53+
Warning Failed 2m (x3 over 4m) kubelet Error: ImagePullBackOff
54+
```
55+
56+
## 해설
57+
58+
### 원인 분석
59+
60+
Events의 이미지 태그를 주의 깊게 보면 `v2.5.O`로 되어 있습니다. 마지막 문자가 숫자 `0`(영)이 아니라 영문 대문자 `O`입니다. 존재하지 않는 태그이므로 이미지 풀에 실패합니다.
61+
62+
롤링 업데이트 전략에 의해 새 Pod가 Ready가 될 때까지 기존 Pod를 유지하고 있지만, `maxUnavailable` 설정에 따라 기존 Pod도 곧 제거될 수 있어 빠른 롤백이 필요합니다.
63+
64+
### 해결 방법
65+
66+
```bash
67+
# 1. 즉시 이전 정상 버전으로 롤백
68+
kubectl rollout undo deployment/api-server --to-revision=2
69+
70+
# 2. 롤백 완료 확인
71+
kubectl rollout status deployment/api-server
72+
73+
# 3. 모든 Pod가 정상 Running인지 확인
74+
kubectl get pods -l app=api-server
75+
76+
# 4. 이후 올바른 태그로 재배포
77+
kubectl set image deployment/api-server api=registry.example.com/api-server:v2.5.0
78+
```
79+
80+
### 실무 팁
81+
82+
이미지 태그 오타는 발견하기 어려운 실수입니다. CI/CD 파이프라인에서 이미지 태그를 변수로 관리하고, 배포 전에 `docker manifest inspect` 또는 레지스트리 API로 태그 존재 여부를 검증하는 단계를 추가하면 예방할 수 있습니다. 또한 `kubectl rollout undo` 명령을 숙지해 두면 장애 시 빠른 복구가 가능합니다.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
id: "kubernetes-027"
3+
title: "HPA가 메트릭을 읽지 못해 스케일링하지 않는 문제"
4+
category: "kubernetes"
5+
difficulty: 2
6+
tags: ["hpa", "autoscaling", "metrics-server", "resource-requests"]
7+
hints:
8+
- "kubectl describe hpa 출력에서 Metrics 섹션의 에러 메시지를 확인하세요."
9+
- "metrics-server가 설치되어 있고 정상 동작하는지 확인하세요."
10+
- "HPA가 메트릭을 읽으려면 대상 Pod에 resource requests가 설정되어 있어야 합니다."
11+
---
12+
13+
## 상황
14+
15+
트래픽 증가에 대비해 HPA(HorizontalPodAutoscaler)를 설정했지만 CPU 사용률이 90%를 넘어도 Pod가 스케일아웃되지 않습니다. HPA의 현재 상태가 `<unknown>/50%`로 표시됩니다. 제공된 정보를 분석하여 원인을 찾으세요.
16+
17+
## 데이터
18+
19+
### kubectl get hpa 출력
20+
21+
```bash
22+
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
23+
web-app-hpa Deployment/web-app <unknown>/50% 2 10 2 15m
24+
```
25+
26+
### kubectl describe hpa web-app-hpa (발췌)
27+
28+
```yaml
29+
Metrics:
30+
Resource cpu on pods (as a percentage of request): <unknown> / 50%
31+
Conditions:
32+
Type Status Reason Message
33+
---- ------ ------ -------
34+
AbleToScale True SucceededGetScale the HPA controller was able to get the target's current scale
35+
ScalingActive False FailedGetResourceMetric the HPA was unable to compute the replica count: failed to get cpu utilization: missing request for cpu in container "web" of Pod "web-app-6d8f9c4b7-k3m2n"
36+
Events:
37+
Type Reason Age From Message
38+
---- ------ ---- ---- -------
39+
Warning FailedComputeMetricsReplicas 12s (x15 over 14m) horizontal-pod-autoscaler failed to get cpu utilization: missing request for cpu
40+
```
41+
42+
### Deployment 스펙 (발췌)
43+
44+
```yaml
45+
spec:
46+
replicas: 2
47+
template:
48+
spec:
49+
containers:
50+
- name: web
51+
image: registry.example.com/web-app:v1.2.0
52+
ports:
53+
- containerPort: 8080
54+
resources:
55+
limits:
56+
cpu: "500m"
57+
memory: "256Mi"
58+
# requests 섹션 없음
59+
```
60+
61+
### kubectl top pods 출력
62+
63+
```bash
64+
NAME CPU(cores) MEMORY(bytes)
65+
web-app-6d8f9c4b7-k3m2n 456m 180Mi
66+
web-app-6d8f9c4b7-r8n5p 478m 175Mi
67+
```
68+
69+
## 해설
70+
71+
### 원인 분석
72+
73+
HPA의 에러 메시지가 원인을 정확히 알려줍니다:
74+
75+
> `missing request for cpu in container "web"`
76+
77+
HPA는 CPU 사용률을 **requests 대비 백분율**로 계산합니다. Deployment 스펙을 보면 `resources.limits`는 설정되어 있지만 `resources.requests`**누락**되어 있습니다. requests가 없으면 HPA가 "현재 CPU가 목표 대비 몇 %인지"를 계산할 수 없어 `<unknown>`으로 표시됩니다.
78+
79+
`kubectl top pods`에서 실제 CPU 사용량이 456m~478m으로 높은 상태임에도 불구하고, HPA는 메트릭을 읽지 못해 스케일링 결정을 내릴 수 없습니다.
80+
81+
### 해결 방법
82+
83+
```bash
84+
# 1. Deployment에 resource requests 추가
85+
kubectl edit deployment web-app
86+
# containers[0].resources에 requests 추가:
87+
# resources:
88+
# requests:
89+
# cpu: "200m"
90+
# memory: "128Mi"
91+
# limits:
92+
# cpu: "500m"
93+
# memory: "256Mi"
94+
95+
# 2. Pod가 재생성된 후 HPA 상태 확인
96+
kubectl get hpa web-app-hpa
97+
98+
# 3. 정상적으로 TARGETS에 백분율이 표시되는지 확인
99+
# 예: 228%/50% → 즉시 스케일아웃 시작
100+
```
101+
102+
### 실무 팁
103+
104+
HPA를 사용할 때는 반드시 대상 컨테이너에 `resources.requests`를 설정하세요. requests 없이 limits만 설정하면 HPA뿐 아니라 스케줄러의 리소스 할당도 예측하기 어려워집니다. 일반적으로 requests는 평균 사용량, limits는 최대 허용량으로 설정하는 것이 좋습니다.

0 commit comments

Comments
 (0)