Ver3.5 ๐ K8s Pod ์ฌ์์ ์ ์ฑ ์์ ์ ๋ณต: restartPolicy๋ฅผ ๋ด ์์์!

๐ K8s Pod ์ฌ์์ ์ ์ฑ ์์ ์ ๋ณต: restartPolicy๋ฅผ ๋ด ์์์!
์ฟ ๋ฒ๋คํฐ์ค Pod๊ฐ ์ฃฝ์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ์ฌ์์ ์ ์ฑ ์ ๋ชจ๋ ๊ฒ์ ์น๊ตฌ์ฒ๋ผ ์ฝ๊ฒ ํํค์ณ๋ณด์ ๐
์ฟ ๋ฒ๋คํฐ์ค(Kubernetes, ์ค์ฌ์ K8s)๋ฅผ ์ฒ์ ๋ฐฐ์ธ ๋ ๋๊ตฌ๋ ํ ๋ฒ์ฏค ์ด๋ฐ ์ํฉ์ ๊ฒช์ด๋ดค์ ๊ฑฐ์ผ. ์ด์ฌํ ๋ฐฐํฌํ Pod๊ฐ ๊ฐ์๊ธฐ CrashLoopBackOff ์ํ๊ฐ ๋๊ฑฐ๋, ์๋๋ฉด ๋ฐฐ์น ์์ ์ ๋๋ ธ๋๋ฐ ์์ ์ด ๋๋ฌ์์๋ ๋ถ๊ตฌํ๊ณ Pod๊ฐ ๊ณ์ ์ฌ์์์ ๋ฐ๋ณตํ๋ ํฉ๋นํ ๊ฒฝํ ๋ง์ด์ผ. ๐
์ด๋ฐ ์ํฉ์ด ์ ์๊ธฐ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ์ ์ดํ ์ ์๋์ง๋ฅผ ์ดํดํ๋ ค๋ฉด Pod์ ์ฌ์์ ์ ์ฑ (restartPolicy)์ ์ ๋๋ก ์์์ผ ํด. ์ค๋์ ์ด ์ฃผ์ ๋ฅผ ์์ ํ ๋ฏ์ด๋ณด๋ฉด์, ์ค๋ฌด์์ ๋ฐ๋ก ์จ๋จน์ ์ ์๋ ์์ค๊น์ง ๊ฐ์ด ํํค์ณ๋ณด์!
restartPolicy 3๊ฐ์ง Pod ์๋ช ์ฃผ๊ธฐ CrashLoopBackOff ํด๊ฒฐ ์ค์ YAML ์์ Job/CronJob ์ฐ๊ณ ๋ฐฑ์คํ ์๊ณ ๋ฆฌ์ฆ
์ฟ ๋ฒ๋คํฐ์ค์์ Pod๋ ํ๋ ์ด์์ ์ปจํ ์ด๋๋ฅผ ๋ฌถ์ด์ ์คํํ๋ ๊ฐ์ฅ ์์ ๋ฐฐํฌ ๋จ์์ผ. ๊ทธ๋ฐ๋ฐ ์ปจํ ์ด๋๋ ์ธ์ ๋ ์ง ์ฃฝ์ ์ ์์ด. ์ฑ ๋ฒ๊ทธ๋ก ์ธํ ํฌ๋์, ๋ฉ๋ชจ๋ฆฌ ์ด๊ณผ(OOM Kill), ์ธ๋ถ ์ ํธ(SIGTERM, SIGKILL), ํน์ ๊ทธ๋ฅ ์์ ์ด ์๋ฃ๋์ด์ ์ ์ ์ข ๋ฃ๋๋ ๊ฒฝ์ฐ๊น์ง ๋ค์ํ ์ด์ ๋ก ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋ ์ ์๊ฑฐ๋ .
์ด๋ ์ฟ ๋ฒ๋คํฐ์ค๊ฐ "์ด ์ปจํ ์ด๋๋ฅผ ๋ค์ ์ด๋ฆด๊น ๋ง๊น?"๋ฅผ ๊ฒฐ์ ํ๋ ๊ธฐ์ค์ด ๋ฐ๋ก restartPolicy์ผ. ์ด ์ค์ ํ๋๊ฐ ์์คํ ์ ์์ ์ฑ๊ณผ ์ด์ ๋ฐฉ์์ ์์ฒญ๋ ์ํฅ์ ๋ฏธ์น๊ธฐ ๋๋ฌธ์, ์ ๋๋ก ์ดํดํ๊ณ ์ฐ๋ ๊ฒ ์ ๋ง ์ค์ํด!
restartPolicy๋ Pod ์คํ(spec)์ ์ ์ํ๋ ํ๋๋ก, Pod ๋ด์ ์ปจํ
์ด๋๊ฐ ์ข
๋ฃ๋์์ ๋ kubelet์ด ์ด๋ป๊ฒ ๋ฐ์ํ ์ง๋ฅผ ๊ฒฐ์ ํด. ์ฝ๊ฒ ๋งํ๋ฉด "์ปจํ
์ด๋๊ฐ ์ฃฝ์ผ๋ฉด ์ด๋ป๊ฒ ํ ๋?"์ ๋ํ ๋ต๋ณ์ด์ผ.
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
restartPolicy: Always # โ ๋ฐ๋ก ์ด ๋ถ๋ถ!
containers:
- name: my-container
image: nginx:latest์์น๋ฅผ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, restartPolicy๋ Pod ๋ ๋ฒจ์์ ์ค์ ํด. ์ฆ, Pod ์์ ์๋ ๋ชจ๋ ์ปจํ
์ด๋์ ๋์ผํ๊ฒ ์ ์ฉ๋ผ. ์ปจํ
์ด๋๋ณ๋ก ๋ค๋ฅด๊ฒ ์ค์ ํ๋ ๊ฑด ๋ถ๊ฐ๋ฅํด. ์ด ์ ์ ๊ผญ ๊ธฐ์ตํด๋์!
restartPolicy๋ Pod ์ ์ฒด์ ์ ์ฉ๋๋ ์ค์ ์ด์ผ. Pod ์์ ์ปจํ
์ด๋๊ฐ 3๊ฐ ์๋ค๋ฉด, 3๊ฐ ๋ชจ๋ ๊ฐ์ ์ฌ์์ ์ ์ฑ
์ ๋ฐ๋ฅด๊ฒ ๋ผ. ์ปจํ
์ด๋๋ง๋ค ๋ค๋ฅธ ์ ์ฑ
์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด, ๋ณ๋์ Pod๋ก ๋ถ๋ฆฌํด์ผ ํด.
restartPolicy์๋ ๋ฑ ์ธ ๊ฐ์ง ๊ฐ๋ง ์ฌ ์ ์์ด. ์ด ์ธ ๊ฐ์ง๊ฐ ์ ๋ถ์ผ!
| ์ ์ฑ | ์ฌ์์ ์กฐ๊ฑด | ๊ธฐ๋ณธ๊ฐ ์ฌ๋ถ | ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก |
|---|---|---|---|
| Always | ์ข ๋ฃ ์ด์ ๋ถ๋ฌธ, ํญ์ ์ฌ์์ | โ ๊ธฐ๋ณธ๊ฐ | ์น์๋ฒ, API ์๋ฒ, ๋ฐ๋ชฌ ํ๋ก์ธ์ค |
| OnFailure | ๋น์ ์ ์ข ๋ฃ(exit code โ 0)์ผ ๋๋ง | โ | ๋ฐฐ์น ์์ , ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ |
| Never | ์ ๋ ์ฌ์์ ์ ํจ | โ | ๋๋ฒ๊น , ๋จ๋ฐ์ฑ ์์ , ๋ก๊ทธ ์์ง |
๊ธฐ๋ณธ๊ฐ์ด Always๋ผ๋ ์ ์ด ์ค์ํด. ์ฆ, restartPolicy๋ฅผ ๋ช
์ํ์ง ์์ผ๋ฉด ์๋์ผ๋ก Always๊ฐ ์ ์ฉ๋ผ. ์ด๊ฒ ์ ์ค์ํ๋๋ฉด, ๋ฐฐ์น ์์
์ ๋ง๋ค ๋ ์ค์๋ก restartPolicy๋ฅผ ๋น ๋จ๋ฆฌ๋ฉด ์์
์ด ๋๋๋ ๊ณ์ ์ฌ์์ํ๋ ๋ฌดํ๋ฃจํ์ ๋น ์ง ์ ์๊ฑฐ๋ ! ๐ฑ
Always๋ ๋ง ๊ทธ๋๋ก "ํญ์ ์ฌ์์"์ด์ผ. ์ปจํ ์ด๋๊ฐ ์ด๋ค ์ด์ ๋ก ์ข ๋ฃ๋๋ ์๊ด์์ด kubelet์ด ๋ฌด์กฐ๊ฑด ๋ค์ ์ด๋ ค์ค. ์ ์ ์ข ๋ฃ(exit code 0)๋ , ์๋ฌ ์ข ๋ฃ(exit code โ 0)๋ , ์ฌ์ง์ด ์ธ๋ถ์์ ๊ฐ์ ๋ก ์ฃฝ์๋ ์๊ด์์ด.
apiVersion: v1
kind: Pod
metadata:
name: always-restart-pod
spec:
restartPolicy: Always
containers:
- name: web-server
image: nginx:1.25
ports:
- containerPort: 80Always ์ ์ฑ ์ ์ฅ๊ธฐ ์คํ ์๋น์ค์ ๋ฑ์ด์ผ. ์น ์๋ฒ, API ์๋ฒ, ๋ฉ์์ง ํ ์ปจ์๋จธ์ฒ๋ผ "ํญ์ ์ด์์์ด์ผ ํ๋" ์๋น์ค๋ค์ด ์ฌ๊ธฐ์ ํด๋นํด.
โข ์น ์๋ฒ (nginx, apache)
โข API ์๋ฒ (Spring Boot, FastAPI)
โข ๋ฐ์ดํฐ๋ฒ ์ด์ค (MySQL, Redis)
โข ๋ฉ์์ง ๋ธ๋ก์ปค (Kafka, RabbitMQ)
โข ๋ชจ๋ํฐ๋ง ์์ด์ ํธ
โข ์ฌ์ด๋์นด ์ปจํ ์ด๋
โข ๋ฐฐ์น ์ฒ๋ฆฌ ์์
โข ๋ฐ์ดํฐ ๋ง์ด๊ทธ๋ ์ด์
โข ์ผํ์ฑ ์ด๊ธฐํ ์คํฌ๋ฆฝํธ
โข ๋๋ฒ๊น ๋ชฉ์ ์ปจํ ์ด๋
โข ํฌ๋ก ์์
โข ์๋ฃ ํ ์ข ๋ฃ๋์ด์ผ ํ๋ ์์
Always ์ ์ฑ ์ ์ธ ๋ ๊ฐ์ฅ ์์ฃผ ๋ง์ฃผ์น๋ ์ํฉ์ด ๋ฐ๋ก CrashLoopBackOff์ผ. ์ด๊ฒ ๋ญ์ง ์ ๋๋ก ์์๋ณด์.
์ปจํ ์ด๋๊ฐ ๊ณ์ ํฌ๋์๋๋ฉด ์ฟ ๋ฒ๋คํฐ์ค๋ ๋ฌดํ์ ์ฆ์ ์ฌ์์ํ์ง ์์. ๋์ ์ง์ ๋ฐฑ์คํ(Exponential Backoff) ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฉํด์ ์ฌ์์ ๊ฐ๊ฒฉ์ ์ ์ ๋๋ ค๋๊ฐ.
| ์ฌ์์ ํ์ | ๋๊ธฐ ์๊ฐ | ๋์ ์๊ฐ |
|---|---|---|
| 1๋ฒ์งธ | 10์ด | 10์ด |
| 2๋ฒ์งธ | 20์ด | 30์ด |
| 3๋ฒ์งธ | 40์ด | 70์ด |
| 4๋ฒ์งธ | 80์ด | 150์ด |
| 5๋ฒ์งธ ์ดํ | ์ต๋ 300์ด(5๋ถ) | ๊ณ์ ์ฆ๊ฐ |
์ด๋ ๊ฒ ์ฌ์์ ๊ฐ๊ฒฉ์ด ๋์ด๋๋ฉด์ Pod ์ํ๊ฐ CrashLoopBackOff๋ก ํ์๋ผ. "ํฌ๋์ ๋ฃจํ ๋ฐฑ์คํ"๋ "ํฌ๋์๊ฐ ๋ฐ๋ณต๋์ด ๋ฐฑ์คํ(๋๊ธฐ) ์ค"์ด๋ผ๋ ๋ป์ด์ผ. ์๋ฌ๊ฐ ์๋๋ผ ์ํ ํ์์ผ!
kubectl logs <pod-name> --previous ๋ช
๋ น์ด๋ก ์ด์ ์ปจํ
์ด๋์ ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์์ด.kubectl describe pod <pod-name>์ผ๋ก ์ด๋ฒคํธ ํ์คํ ๋ฆฌ๋ ๋ณผ ์ ์๊ณ .๋ฐฑ์คํ ํ์ด๋จธ๋ ์ปจํ ์ด๋๊ฐ 10๋ถ ์ด์ ์ ์ ์คํ๋๋ฉด ๋ฆฌ์ ๋ผ!
OnFailure๋ ์ปจํ ์ด๋๊ฐ ๋น์ ์ ์ข ๋ฃ๋์์ ๋๋ง ์ฌ์์ํด. "๋น์ ์ ์ข ๋ฃ"์ ๊ธฐ์ค์ exit code๊ฐ 0์ด ์๋ ๊ฒฝ์ฐ์ผ.
๋ฆฌ๋ ์ค/์ ๋์ค ์์คํ ์์ ํ๋ก์ธ์ค๊ฐ ์ข ๋ฃ๋ ๋ exit code๋ฅผ ๋ฐํํ๋๋ฐ:
โข ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋จ
โข ์๋์ ์ผ๋ก ์ข ๋ฃ๋จ
โข OnFailure: ์ฌ์์ โ
โข Never: ์ฌ์์ โ
โข ํ๋ก๊ทธ๋จ ์๋ฌ ๋ฐ์
โข ์์ธ ์ฒ๋ฆฌ ์คํจ
โข OOM Kill (exit code 137)
โข OnFailure: ์ฌ์์ โ
โข Never: ์ฌ์์ โ
apiVersion: v1
kind: Pod
metadata:
name: batch-job-pod
spec:
restartPolicy: OnFailure
containers:
- name: batch-processor
image: my-batch-app:1.0
command: ["python", "process_data.py"]
env:
- name: DATA_SOURCE
value: "s3://my-bucket/data"OnFailure๊ฐ ๋น์ ๋ฐํ๋ ์ํฉ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ดํด๋ณด์.
์๋๋ฆฌ์ค 1: ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐฐ์น ์์
๋งค์ผ ๋ฐค 10๋ง ๊ฑด์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฐ์น ์์ ์ด ์๋ค๊ณ ํด๋ณด์. ์ด ์์ ์ ์ฑ๊ณตํ๋ฉด exit code 0์ผ๋ก ์ข ๋ฃ๋๊ณ , ์คํจํ๋ฉด exit code 1๋ก ์ข ๋ฃ๋ผ.
apiVersion: v1
kind: Pod
metadata:
name: nightly-batch
spec:
restartPolicy: OnFailure
containers:
- name: data-processor
image: data-processor:latest
command:
- /bin/sh
- -c
- |
python process.py && echo "์ฑ๊ณต!" && exit 0
# ์คํจ ์ exit 1 ๋ฐํ โ ์ฌ์์
# ์ฑ๊ณต ์ exit 0 ๋ฐํ โ ์ฌ์์ ์ ํจ์ด ๊ฒฝ์ฐ ์์ ์ด ์ฑ๊ณตํ๋ฉด Pod๋ Completed ์ํ๊ฐ ๋๊ณ ์ฌ์์ํ์ง ์์. ํ์ง๋ง ๋คํธ์ํฌ ์ค๋ฅ๋ ์ผ์์ ์ธ DB ์ฐ๊ฒฐ ์คํจ๋ก ์์ ์ด ์คํจํ๋ฉด ์๋์ผ๋ก ์ฌ์์ํด์ ๋ค์ ์๋ํด. ์๋ฒฝํ์ง ์์? ๐
์๋๋ฆฌ์ค 2: ์ด๊ธฐํ ์์ (Init Container ๋์)
apiVersion: v1
kind: Pod
metadata:
name: db-migration-pod
spec:
restartPolicy: OnFailure
containers:
- name: migrator
image: flyway:9.0
command: ["flyway", "migrate"]
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://db:5432/mydb"
- name: FLYWAY_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username์ฌ์ค ์ค๋ฌด์์ OnFailure๋ฅผ ๋จ๋ Pod์ ์ฐ๋ ๊ฒฝ์ฐ๋ ๋ง์ง ์์. ๋๋ถ๋ถ Job ๋ฆฌ์์ค์ ํจ๊ป ์ฌ์ฉํด. Job์ ๋ฐฐ์น ์์ ์ ๊ด๋ฆฌํ๋ ์ฟ ๋ฒ๋คํฐ์ค ๋ฆฌ์์ค์ธ๋ฐ, Job์ ๊ธฐ๋ณธ restartPolicy๊ฐ ๋ฐ๋ก OnFailure์ผ!
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration-job
spec:
completions: 1 # ์ฑ๊ณต์ ์ผ๋ก ์๋ฃํด์ผ ํ ํ์
parallelism: 1 # ๋์์ ์คํํ Pod ์
backoffLimit: 4 # ์ต๋ ์ฌ์๋ ํ์
template:
spec:
restartPolicy: OnFailure # Job์์๋ OnFailure ๋๋ Never๋ง ๊ฐ๋ฅ!
containers:
- name: migrator
image: my-migrator:1.0
command: ["./migrate.sh"]restartPolicy: Always๋ฅผ ์ฌ์ฉํ ์ ์์ด. Job์ ์์
์ด ์๋ฃ๋๋ฉด ๋๋์ผ ํ๋ ๋ฆฌ์์ค์ธ๋ฐ, Always๋ฅผ ์ฐ๋ฉด ์์ํ ์ฌ์์ํ๋ ๋ชจ์์ด ์๊ธฐ๊ฑฐ๋ . Job์์๋ OnFailure ๋๋ Never๋ง ์ฌ์ฉ ๊ฐ๋ฅํด!
OnFailure๋ฅผ Job๊ณผ ํจ๊ป ์ธ ๋ backoffLimit์ด๋ผ๋ ์ค์ํ ์ค์ ์ด ์์ด. ์ด๊ฑด "์ต๋ ๋ช ๋ฒ๊น์ง ์ฌ์๋ํ ๊ฑฐ์ผ?"๋ฅผ ์ ํ๋ ๊ฑฐ์ผ.
spec:
backoffLimit: 6 # ๊ธฐ๋ณธ๊ฐ์ 6
# 6๋ฒ ์คํจํ๋ฉด Job ์์ฒด๊ฐ Failed ์ํ๊ฐ ๋จbackoffLimit์ ์ด๊ณผํ๋ฉด Job์ Failed ์ํ๊ฐ ๋๊ณ , ๋ ์ด์ ์ฌ์๋ํ์ง ์์. ์ด๋ ์๋ฆผ์ ๋ฐ์์ ์๋์ผ๋ก ํ์ธํ๋ ๊ฒ ์ข์ ์ด์ ๋ฐฉ์์ด์ผ.
Never๋ ๊ฐ์ฅ ๋จ์ํด. ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋๋ฉด ์ด์ ๋ถ๋ฌธํ๊ณ ์ ๋ ์ฌ์์ํ์ง ์์. ์ ์ ์ข ๋ฃ๋ ๋น์ ์ ์ข ๋ฃ๋ ์๊ด์์ด ๊ทธ๋ฅ ๋์ด์ผ.
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
restartPolicy: Never
containers:
- name: debugger
image: busybox:latest
command: ["sh", "-c", "env && ls -la /app && cat /app/config.yaml"]Never๋ ์ธ์ ์จ์ผ ํ ๊น? ์๊ฐ๋ณด๋ค ๊ฝค ์ ์ฉํ ์ํฉ๋ค์ด ์์ด.
1. ๋๋ฒ๊น ๋ชฉ์
ํ๋ก๋์ ํ๊ฒฝ์์ ํน์ Pod์ ํ๊ฒฝ ๋ณ์๋ ํ์ผ ์์คํ ์ ํ์ธํ๊ณ ์ถ์ ๋, Never๋ก ์ค์ ํ ์์ Pod๋ฅผ ๋์์ ํ์ธํ๊ณ ๋ฐ๋ก ์ข ๋ฃ์ํฌ ์ ์์ด. ์ฌ์์ ์์ด ํ ๋ฒ๋ง ์คํ๋๋๊น ๊น๋ํ์ง!
# ํ๊ฒฝ ๋ณ์ ๋คํ์ฉ ๋๋ฒ๊ทธ Pod
apiVersion: v1
kind: Pod
metadata:
name: env-debugger
namespace: production
spec:
restartPolicy: Never
containers:
- name: debugger
image: alpine:latest
command: ["sh", "-c", "printenv | sort > /tmp/env.txt && cat /tmp/env.txt"]
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secrets2. ๋จ๋ฐ์ฑ ๋ง์ด๊ทธ๋ ์ด์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ๋ง์ด๊ทธ๋ ์ด์ ์ฒ๋ผ ๋ฑ ํ ๋ฒ๋ง ์คํ๋์ด์ผ ํ๋ ์์ ์ Never๊ฐ ์ ํฉํด. ์ฑ๊ณตํ๋ ์คํจํ๋ ์ฌ์์ ์์ด ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๊ณ ์ถ์ ๋ ์จ.
3. Job์์์ Never ํ์ฉ
apiVersion: batch/v1
kind: Job
metadata:
name: one-time-task
spec:
backoffLimit: 0 # ์ฌ์๋ ์์
template:
spec:
restartPolicy: Never # Pod ๋ ๋ฒจ์์๋ ์ฌ์์ ์์
containers:
- name: task
image: my-task:1.0
command: ["./run-once.sh"]Job์์ restartPolicy: Never์ backoffLimit: 0์ ํจ๊ป ์ฐ๋ฉด "๋ฑ ํ ๋ฒ๋ง ์๋ํ๊ณ , ์คํจํด๋ ์ฌ์๋ ์์"์ด ๋ผ. ์์ ํ ๋จ๋ฐ์ฑ ์คํ์ด์ผ!
โข Never: ์คํจํด๋ ์ฌ์๋ ์์ด ๊ฒฐ๊ณผ๋ฅผ ์ง์ ํ์ธํ๊ณ ์ถ์ ๋
โข OnFailure: ์ผ์์ ์ค๋ฅ(๋คํธ์ํฌ, DB ์ฐ๊ฒฐ ๋ฑ)๊ฐ ์์ด๋ ์๋์ผ๋ก ์ฌ์๋ํ๊ธธ ์ํ ๋
๋ฉฑ๋ฑ์ฑ(idempotent)์ด ๋ณด์ฅ๋๋ ์์ ์ด๋ผ๋ฉด OnFailure๊ฐ ๋ ์์ ํด. ๋ฉฑ๋ฑ์ฑ์ด ์๋ ์์ (์: ์ด๋ฉ์ผ ๋ฐ์ก)์ด๋ผ๋ฉด Never๊ฐ ๋ ์ ํฉํ ์ ์์ด.
restartPolicy๋ฅผ ์ ๋๋ก ์ดํดํ๋ ค๋ฉด Pod์ ์๋ช ์ฃผ๊ธฐ(Lifecycle)๋ฅผ ์์์ผ ํด. Pod๋ ๋ค์๊ณผ ๊ฐ์ Phase(๋จ๊ณ)๋ฅผ ๊ฑฐ์ณ.
| Phase | ์ค๋ช | restartPolicy ์ํฅ |
|---|---|---|
| Pending | Pod๊ฐ ์๋ฝ๋์ง๋ง ์ปจํ ์ด๋๊ฐ ์์ง ์คํ ์ ๋จ. ์ด๋ฏธ์ง ๋ค์ด๋ก๋ ์ค์ด๊ฑฐ๋ ์ค์ผ์ค๋ง ๋๊ธฐ ์ค. | ์ํฅ ์์ |
| Running | Pod๊ฐ ๋ ธ๋์ ๋ฐ์ธ๋ฉ๋๊ณ , ๋ชจ๋ ์ปจํ ์ด๋๊ฐ ์์ฑ๋จ. ์ต์ ํ๋์ ์ปจํ ์ด๋๊ฐ ์คํ ์ค์ด๊ฑฐ๋ ์์/์ฌ์์ ์ค. | ์ปจํ ์ด๋ ์ข ๋ฃ ์ ์ ์ฑ ์ ์ฉ |
| Succeeded | Pod์ ๋ชจ๋ ์ปจํ ์ด๋๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ข ๋ฃ๋จ(exit code 0). ์ฌ์์๋์ง ์์. | Always๋ฉด ์ด ์ํ ์ ๋จ |
| Failed | Pod์ ๋ชจ๋ ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋๋๋ฐ, ์ต์ ํ๋๊ฐ ์คํจ๋ก ์ข ๋ฃ๋จ. | Always/OnFailure๋ฉด ์ด ์ํ ์ ๋จ |
| Unknown | Pod ์ํ๋ฅผ ์ ์ ์์. ๋ณดํต ๋ ธ๋์์ ํต์ ์ค๋ฅ. | ์ํฅ ์์ |
Pod Phase์ ๋ณ๊ฐ๋ก ๊ฐ ์ปจํ
์ด๋๋ ์์ฒด์ ์ธ ์ํ๋ฅผ ๊ฐ์ ธ. kubectl describe pod๋ก ํ์ธํ ์ ์์ด.
| ์ปจํ ์ด๋ ์ํ | ์ค๋ช |
|---|---|
| Waiting | ์ปจํ ์ด๋๊ฐ ์์ง ์คํ ์ค์ด ์๋. ์ด๋ฏธ์ง ํ๋ง, ์ํฌ๋ฆฟ ์ ์ฉ ๋ฑ ๋๊ธฐ ์ค. |
| Running | ์ปจํ ์ด๋๊ฐ ๋ฌธ์ ์์ด ์คํ ์ค. startedAt ํ์์คํฌํ ํฌํจ. |
| Terminated | ์ปจํ ์ด๋๊ฐ ์คํ์ ์๋ฃํ๊ฑฐ๋ ์ด๋ค ์ด์ ๋ก ์คํจํจ. exit code, ์์/์ข ๋ฃ ์๊ฐ ํฌํจ. |
# ์ปจํ
์ด๋ ์ํ ํ์ธ
kubectl describe pod my-pod
# ์ถ๋ ฅ ์์:
# Containers:
# my-container:
# State: Terminated
# Reason: Error
# Exit Code: 1
# Started: Mon, 01 Jan 2024 10:00:00 +0000
# Finished: Mon, 01 Jan 2024 10:00:05 +0000
# Last State: Terminated
# Reason: Error
# Exit Code: 1
# Ready: False
# Restart Count: 3์ค์ ํ๋ก๋์ ์์ ์ธ ์ ์๋ ์์ค์ YAML์ด์ผ. Deployment์ ํจ๊ป ์ฌ์ฉํ๋ ํจํด์ด์ผ.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-api-deployment
namespace: production
labels:
app: web-api
version: "1.0"
spec:
replicas: 3
selector:
matchLabels:
app: web-api
template:
metadata:
labels:
app: web-api
spec:
restartPolicy: Always # Deployment๋ Always๋ง ๊ฐ๋ฅ
containers:
- name: api-server
image: my-api:1.0.0
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5apiVersion: batch/v1
kind: Job
metadata:
name: monthly-report-job
namespace: batch
spec:
completions: 1
parallelism: 1
backoffLimit: 3 # ์ต๋ 3๋ฒ ์ฌ์๋
activeDeadlineSeconds: 3600 # 1์๊ฐ ๋ด์ ์๋ฃ ์ ๋๋ฉด ์คํจ
template:
metadata:
labels:
job-name: monthly-report
spec:
restartPolicy: OnFailure
containers:
- name: report-generator
image: report-gen:2.1
command: ["python", "-u", "generate_report.py"]
env:
- name: REPORT_MONTH
value: "2024-01"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: host
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
restartPolicy: OnFailureapiVersion: batch/v1
kind: CronJob
metadata:
name: daily-cleanup
namespace: maintenance
spec:
schedule: "0 2 * * *" # ๋งค์ผ ์๋ฒฝ 2์
concurrencyPolicy: Forbid # ์ด์ ์์
์ด ๋๋์ง ์์ผ๋ฉด ์ ์์
์์ ์ ํจ
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup-worker
image: cleanup:latest
command:
- /bin/sh
- -c
- |
echo "์ ๋ฆฌ ์์
์์: $(date)"
python cleanup_old_data.py --days 90
echo "์ ๋ฆฌ ์์
์๋ฃ: $(date)"apiVersion: v1
kind: Pod
metadata:
name: debug-session
namespace: production
annotations:
purpose: "์์ ๋๋ฒ๊น
- ์ฌ์ฉ ํ ์ญ์ ํ์"
spec:
restartPolicy: Never
serviceAccountName: debug-sa
containers:
- name: debugger
image: nicolaka/netshoot:latest # ๋คํธ์ํฌ ๋๋ฒ๊น
๋๊ตฌ ํฌํจ
command: ["sleep", "3600"] # 1์๊ฐ ๋์ ์ ์ง
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_PTRACE"]
tolerations:
- operator: "Exists" # ๋ชจ๋ ๋
ธ๋์ ์ค์ผ์ค ๊ฐ๋ฅ
# ์ฌ์ฉ ํ: kubectl delete pod debug-session -n productionInit Container๋ ๋ฉ์ธ ์ปจํ ์ด๋๊ฐ ์์๋๊ธฐ ์ ์ ์คํ๋๋ ํน์ ์ปจํ ์ด๋์ผ. Init Container์ ์ฌ์์ ๋์์ Pod์ restartPolicy์ ๋ฐ๋ผ ๋ฌ๋ผ์ ธ.
apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
restartPolicy: Always
initContainers:
- name: wait-for-db
image: busybox:latest
command:
- sh
- -c
- |
until nc -z db-service 5432; do
echo "DB ๋๊ธฐ ์ค..."
sleep 2
done
echo "DB ์ฐ๊ฒฐ ํ์ธ!"
- name: run-migrations
image: flyway:9.0
command: ["flyway", "migrate"]
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://db-service:5432/mydb"
containers:
- name: app
image: my-app:1.0
ports:
- containerPort: 8080โข Always: Init Container๊ฐ ์คํจํ๋ฉด ์ฌ์์. ์ฑ๊ณตํ ๋๊น์ง ๊ณ์ ์๋.
โข OnFailure: Init Container๊ฐ ์คํจํ๋ฉด ์ฌ์์. ์ฑ๊ณตํ๋ฉด ๋ค์ ๋จ๊ณ๋ก.
โข Never: Init Container๊ฐ ์คํจํ๋ฉด Pod ์ ์ฒด๊ฐ Failed ์ํ.
Init Container๋ ํญ์ ์์๋๋ก ์คํ๋๊ณ , ์ด์ Init Container๊ฐ ์ฑ๊ณตํด์ผ ๋ค์ Init Container๊ฐ ์์๋ผ!
์ปจํ ์ด๋๊ฐ ๊ณ์ ์คํจํ ๋ ์ฟ ๋ฒ๋คํฐ์ค๊ฐ ๋ฌดํ์ ์ฆ์ ์ฌ์์ํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ์์คํ ๋ฆฌ์์ค๋ฅผ ์์ฒญ๋๊ฒ ๋ญ๋นํ๊ณ , ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์๊ฐ๋ ์์ด ์ฌ์์๋ง ๋ฐ๋ณตํ๊ฒ ๋ผ. ๊ทธ๋์ ์ฟ ๋ฒ๋คํฐ์ค๋ ์ง์ ๋ฐฑ์คํ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด.
๋ฐฑ์คํ ๊ณต์์ ๊ฐ๋จํด: ๋๊ธฐ ์๊ฐ = min(2^n ร 10์ด, 300์ด)
# ๋ฐฑ์คํ ๊ณ์ฐ ์์
1๋ฒ์งธ ์ฌ์์: 2^0 ร 10 = 10์ด
2๋ฒ์งธ ์ฌ์์: 2^1 ร 10 = 20์ด
3๋ฒ์งธ ์ฌ์์: 2^2 ร 10 = 40์ด
4๋ฒ์งธ ์ฌ์์: 2^3 ร 10 = 80์ด
5๋ฒ์งธ ์ฌ์์: 2^4 ร 10 = 160์ด
6๋ฒ์งธ ์ฌ์์: 2^5 ร 10 = 320์ด โ 300์ด(์ต๋)๋ก ์ ํ
7๋ฒ์งธ ์ดํ: ๊ณ์ 300์ด ๊ฐ๊ฒฉ์ค์ํ ์ ์ ๋ฐฑ์คํ ํ์ด๋จธ๊ฐ ๋ฆฌ์ ๋๋ ์กฐ๊ฑด์ด์ผ. ์ปจํ ์ด๋๊ฐ 10๋ถ ์ด์ ์ ์์ ์ผ๋ก ์คํ๋๋ฉด ๋ฐฑ์คํ ์นด์ดํฐ๊ฐ ๋ฆฌ์ ๋ผ. ์ฆ, 10๋ถ ์ด์ ์ด์์๋ค๊ฐ ๋ค์ ์ฃฝ์ผ๋ฉด ์ฒ์๋ถํฐ 10์ด ๋๊ธฐ๋ก ์์ํด.
๋ฐฑ์คํ ๋ฆฌ์ ์กฐ๊ฑด: ์ปจํ ์ด๋๊ฐ 10๋ถ(600์ด) ์ด์ ์ ์ ์คํ
์ด ๋๋ฌธ์ "10๋ถ๋ง๋ค ์ฃฝ๋" ์ปจํ ์ด๋๋ ๋ฐฑ์คํ๊ฐ ๋ฆฌ์ ๋์ด ๊ณ์ 10์ด ๊ฐ๊ฒฉ์ผ๋ก ์ฌ์์์ ๋ฐ๋ณตํ ์ ์์ด. ์ด๋ฐ ํจํด์ ๋ฐ๊ฒฌํ๋ฉด ๊ทผ๋ณธ ์์ธ์ ์ฐพ์์ผ ํด!
CrashLoopBackOff ์ํ์์ ๋น ์ ธ๋์ค๋ ์ค์ ์ ๋ต๋ค์ ์์๋ณด์.
์ ๋ต 1: ๋ก๊ทธ ํ์ธ
# ํ์ฌ ์ปจํ
์ด๋ ๋ก๊ทธ
kubectl logs pod-name -c container-name
# ์ด์ ์ปจํ
์ด๋ ๋ก๊ทธ (ํฌ๋์ ์ง์ ๋ก๊ทธ)
kubectl logs pod-name -c container-name --previous
# ์ค์๊ฐ ๋ก๊ทธ ์คํธ๋ฆฌ๋ฐ
kubectl logs pod-name -f
# ๋ง์ง๋ง 100์ค๋ง
kubectl logs pod-name --tail=100์ ๋ต 2: Pod ์ด๋ฒคํธ ํ์ธ
kubectl describe pod pod-name
# Events ์น์
์์ ํ์ธ:
# Warning BackOff 2m kubelet Back-off restarting failed container
# Normal Pulled 5m kubelet Successfully pulled image
# Warning Failed 5m kubelet Error: OOMKilled์ ๋ต 3: ์์ sleep ๋ช ๋ น์ผ๋ก ์ปจํ ์ด๋ ์ ์ง
# ๋๋ฒ๊น
์ ์ํด ์๋ ๋ช
๋ น ๋์ sleep์ผ๋ก ๊ต์ฒด
kubectl patch pod crashing-pod -p '{"spec":{"containers":[{"name":"app","command":["sleep","infinity"]}]}}'
# ๋๋ ์ Pod๋ฅผ sleep์ผ๋ก ์์ฑ
kubectl run debug-pod --image=my-app:1.0 --command -- sleep infinity
# ๊ทธ ๋ค์ exec๋ก ๋ค์ด๊ฐ์ ์ง์ ํ์ธ
kubectl exec -it debug-pod -- /bin/sh์ ๋ต 4: ๋ฆฌ์์ค ์ ํ ํ์ธ
# OOMKilled ํ์ธ
kubectl describe pod pod-name | grep -A5 "Last State"
# ์ถ๋ ฅ ์์:
# Last State: Terminated
# Reason: OOMKilled โ ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ!
# Exit Code: 137
#
# ํด๊ฒฐ: resources.limits.memory ๊ฐ์ ๋๋ ค์ค์ฟ ๋ฒ๋คํฐ์ค์ ๋ค์ํ ์ํฌ๋ก๋ ๋ฆฌ์์ค๋ค์ ๊ฐ์ ์ง์ํ๋ restartPolicy๊ฐ ๋ฌ๋ผ. ์ด๊ฑธ ๋ชจ๋ฅด๋ฉด YAML ์์ฑํ ๋ ์๋ฌ๋ฅผ ๋ง๋๊ฒ ๋ผ!
| ๋ฆฌ์์ค ์ข ๋ฅ | ์ง์ restartPolicy | ์ด์ |
|---|---|---|
| Deployment | Always๋ง | ํญ์ ์ง์ ๋ ์์ Pod๋ฅผ ์ ์งํด์ผ ํจ |
| ReplicaSet | Always๋ง | ๋ ํ๋ฆฌ์นด ์๋ฅผ ํญ์ ์ ์งํด์ผ ํจ |
| StatefulSet | Always๋ง | ์ํ ์ ์ง ์๋น์ค๋ ํญ์ ์คํ๋์ด์ผ ํจ |
| DaemonSet | Always๋ง | ๋ชจ๋ ๋ ธ๋์์ ํญ์ ์คํ๋์ด์ผ ํจ |
| Job | OnFailure, Never | ์์ ์๋ฃ ํ ์ข ๋ฃ๋์ด์ผ ํจ |
| CronJob | OnFailure, Never | Job์ ์์ฑํ๋ฏ๋ก ๋์ผํ ์ ์ฝ |
| ๋จ๋ Pod | Always, OnFailure, Never | ์ ์ฝ ์์ |
Job์์
restartPolicy: Always๋ฅผ ์ฐ๋ฉด ์ด๋ฐ ์๋ฌ๊ฐ ๋:The Job "my-job" is invalid: spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never"Job ์์ฑํ ๋ ๊ผญ OnFailure ๋๋ Never๋ฅผ ์จ์ผ ํด!
์ฟ ๋ฒ๋คํฐ์ค์๋ ์ปจํ ์ด๋์ ์ํ๋ฅผ ์ฒดํฌํ๋ Probe ๊ธฐ๋ฅ์ด ์์ด. ์ด Probe๊ฐ restartPolicy์ ํจ๊ป ์๋ํ๋ฉด ํจ์ฌ ๊ฐ๋ ฅํ ์๊ฐ ์น์ (Self-healing) ์์คํ ์ ๋ง๋ค ์ ์์ด.
์ธ ๊ฐ์ง ์ฃผ์ Probe๋ฅผ ์์๋ณด์:
"์ปจํ ์ด๋๊ฐ ์ด์์๋?"๋ฅผ ์ฒดํฌ.
์คํจํ๋ฉด ์ปจํ ์ด๋๋ฅผ ์ฌ์์.
๋ฐ๋๋ฝ ์ํ ๊ฐ์ง์ ์ ์ฉ.
"ํธ๋ํฝ ๋ฐ์ ์ค๋น๋๋?"๋ฅผ ์ฒดํฌ.
์คํจํ๋ฉด ์๋น์ค์์ ์ ์ธ.
์ฌ์์์ ํ์ง ์์.
"์ฑ์ด ์์๋๋?"๋ฅผ ์ฒดํฌ.
์ฑ๊ณต ์ ๊น์ง ๋ค๋ฅธ Probe ๋นํ์ฑํ.
๋๋ฆฐ ์์ ์ฑ์ ์ ์ฉ.
apiVersion: v1
kind: Pod
metadata:
name: robust-app
spec:
restartPolicy: Always
containers:
- name: app
image: my-app:1.0
ports:
- containerPort: 8080
# ์์ ์ฒดํฌ: ์ต๋ 5๋ถ(30์ด ร 10ํ) ๋๊ธฐ
startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10
# ์์กด ์ฒดํฌ: ์คํจ ์ ์ปจํ
์ด๋ ์ฌ์์
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 0 # startupProbe ์ฑ๊ณต ํ ์์
periodSeconds: 10
failureThreshold: 3 # 3๋ฒ ์ฐ์ ์คํจ ์ ์ฌ์์
timeoutSeconds: 5
# ์ค๋น ์ฒดํฌ: ์คํจ ์ ์๋น์ค์์ ์ ์ธ (์ฌ์์ ์์)
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
failureThreshold: 3Liveness Probe๊ฐ ์คํจํ๋ฉด kubelet์ด ์ปจํ ์ด๋๋ฅผ ๊ฐ์ ์ข ๋ฃ(kill)ํ๊ณ , restartPolicy์ ๋ฐ๋ผ ์ฌ์์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํด.
# Liveness Probe ์คํจ ์ด๋ฒคํธ ํ์ธ
kubectl describe pod my-pod
# ์ด๋ฒคํธ ์์:
# Warning Unhealthy 5m kubelet Liveness probe failed: HTTP probe failed with statuscode: 503
# Normal Killing 5m kubelet Container app failed liveness probe, will be restarted
# Normal Pulled 4m kubelet Container image "my-app:1.0" already present on machine
# Normal Created 4m kubelet Created container app
# Normal Started 4m kubelet Started container appโข Liveness Probe๋ ๊ฐ๋ณ๊ฒ ๋ง๋ค์ด์ผ ํด. DB ์ฟผ๋ฆฌ๋ ์ธ๋ถ ์๋น์ค ํธ์ถ์ ํผํด.
โข ์ฑ ๋ด๋ถ ์ํ(๋ฐ๋๋ฝ, ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฑ)๋ง ์ฒดํฌํ๋ ๊ฒ ์ด์์ .
โข
failureThreshold๋ฅผ ๋๋ฌด ๋ฎ๊ฒ ์ค์ ํ๋ฉด ์ผ์์ ์ธ ๋ถํ ์ํฉ์์ ๋ถํ์ํ ์ฌ์์์ด ๋ฐ์ํ ์ ์์ด.โข
initialDelaySeconds๋ ์ฑ ์์ ์๊ฐ๋ณด๋ค ์ถฉ๋ถํ ํฌ๊ฒ ์ค์ ํด์ผ ํด. (Startup Probe๋ฅผ ์ฐ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ๋ ์ฐ์ํ๊ฒ ํด๊ฒฐํ ์ ์์ด!)
๊ฐ์ฅ ํํ ์ค์์ผ. ๋ฐฐ์น ์์ ์ ๋จ๋ Pod๋ก ๋ง๋ค๋ฉด์ restartPolicy๋ฅผ ๋ช ์ํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ์ธ Always๊ฐ ์ ์ฉ๋ผ.
# โ ์๋ชป๋ ์์ - ์์
์๋ฃ ํ ๋ฌดํ ์ฌ์์!
apiVersion: v1
kind: Pod
metadata:
name: data-processor
spec:
# restartPolicy ์์ โ ๊ธฐ๋ณธ๊ฐ Always ์ ์ฉ!
containers:
- name: processor
image: my-processor:1.0
command: ["python", "process.py"]
---
# โ
์ฌ๋ฐ๋ฅธ ์์
apiVersion: v1
kind: Pod
metadata:
name: data-processor
spec:
restartPolicy: OnFailure # ๋๋ Never
containers:
- name: processor
image: my-processor:1.0
command: ["python", "process.py"]์ปจํ ์ด๋๊ฐ ๊ณ์ ์ฌ์์๋๋๋ฐ ๋ก๊ทธ์ ์๋ฌด๊ฒ๋ ์๋ค๋ฉด? OOMKilled์ผ ๊ฐ๋ฅ์ฑ์ด ๋์. ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ์ผ๋ก OS๊ฐ ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ ์ข ๋ฃํ ๊ฑฐ์ผ.
# OOMKilled ํ์ธ ๋ฐฉ๋ฒ
kubectl describe pod my-pod | grep -A 10 "Last State"
# ์ถ๋ ฅ:
# Last State: Terminated
# Reason: OOMKilled
# Exit Code: 137 โ 128 + 9(SIGKILL) = 137
# Started: ...
# Finished: ...
# ํด๊ฒฐ: ๋ฉ๋ชจ๋ฆฌ ์ ํ ์ฆ๊ฐ
spec:
containers:
- name: app
resources:
limits:
memory: "1Gi" # ๊ธฐ์กด 512Mi์์ ์ฆ๊ฐ
requests:
memory: "512Mi"์ด๋ฉ์ผ ๋ฐ์ก, ๊ฒฐ์ ์ฒ๋ฆฌ์ฒ๋ผ ํ ๋ฒ๋ง ์คํ๋์ด์ผ ํ๋ ์์ ์ OnFailure๋ฅผ ์ฐ๋ฉด ์ฌ์๋ ์ ์ค๋ณต ์คํ์ด ๋ฐ์ํ ์ ์์ด.
# โ ์ํํ ์์ - ์ด๋ฉ์ผ์ด ์ฌ๋ฌ ๋ฒ ๋ฐ์ก๋ ์ ์์!
apiVersion: batch/v1
kind: Job
metadata:
name: send-newsletter
spec:
template:
spec:
restartPolicy: OnFailure # ์คํจ ์ ์ฌ์๋ โ ์ด๋ฉ์ผ ์ค๋ณต ๋ฐ์ก!
containers:
- name: mailer
image: mailer:1.0
---
# โ
์์ ํ ์์ - ๋ฉฑ๋ฑ์ฑ ์๋ ์์
์ Never ์ฌ์ฉ
apiVersion: batch/v1
kind: Job
metadata:
name: send-newsletter
spec:
backoffLimit: 0 # ์ฌ์๋ ์์
template:
spec:
restartPolicy: Never # ์คํจํด๋ ์ฌ์์ ์์
containers:
- name: mailer
image: mailer:1.0
# ์ฑ ๋ ๋ฒจ์์ ์ค๋ณต ๋ฐฉ์ง ๋ก์ง ๊ตฌํ ํ์# โ ๋๋ฌด ๊ณต๊ฒฉ์ ์ธ ์ค์ - ๋ถํ ์ ๋ถํ์ํ ์ฌ์์ ๋ฐ์
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5 # ๋๋ฌด ์งง์
periodSeconds: 5 # ๋๋ฌด ์์ฃผ
failureThreshold: 1 # 1๋ฒ๋ง ์คํจํด๋ ์ฌ์์!
timeoutSeconds: 1 # ๋๋ฌด ์งง์
---
# โ
์ ์ ํ ์ค์
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30 # ์ฑ ์์ ์๊ฐ ๊ณ ๋ ค
periodSeconds: 10 # 10์ด๋ง๋ค ์ฒดํฌ
failureThreshold: 3 # 3๋ฒ ์ฐ์ ์คํจ ์ ์ฌ์์
timeoutSeconds: 5 # 5์ด ํ์์์restartPolicy๋ ์ปจํ ์ด๋ ๋ ๋ฒจ์ ์ฌ์์์ ์ ์ดํ์ง๋ง, Pod Disruption Budget(PDB)์ ํด๋ฌ์คํฐ ๋ ๋ฒจ์์ Pod์ ๊ฐ์ฉ์ฑ์ ๋ณด์ฅํด. ์ด ๋์ ๋ค๋ฅธ ๊ฐ๋ ์ด์ผ!
# PDB: ์ต์ 2๊ฐ์ Pod๊ฐ ํญ์ ์คํ๋๋๋ก ๋ณด์ฅ
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web-api
# ์ด๊ฑด restartPolicy์ ๋ณ๊ฐ๋ก ๋์ํด!์ด ํ๋ก์ฐ์ฐจํธ๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด ๋๋ถ๋ถ์ ์ํฉ์์ ์ ์ ํ restartPolicy๋ฅผ ์ ํํ ์ ์์ด. ๋ฌผ๋ก ์ค์ ์ํฉ์ ๋ ๋ณต์กํ ์ ์์ผ๋, ๊ฐ ์ ์ฑ ์ ํน์ฑ์ ์ ์ดํดํ๊ณ ์ํฉ์ ๋ง๊ฒ ์ ์ฉํ๋ ๊ฒ ์ค์ํด!
์ฌ์ด๋์นด ํจํด์ ๋ฉ์ธ ์ปจํ ์ด๋ ์์ ๋ณด์กฐ ์ปจํ ์ด๋๋ฅผ ๋ถ์ด๋ ํจํด์ด์ผ. ๋ก๊ทธ ์์ง, ํ๋ก์, ๋ชจ๋ํฐ๋ง ๋ฑ์ ํ์ฉํด.
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
restartPolicy: Always # ๋ชจ๋ ์ปจํ
์ด๋์ ์ ์ฉ
containers:
# ๋ฉ์ธ ์ฑ
- name: main-app
image: my-app:1.0
ports:
- containerPort: 8080
# ๋ก๊ทธ ์์ง ์ฌ์ด๋์นด
- name: log-collector
image: fluentd:v1.16
volumeMounts:
- name: app-logs
mountPath: /var/log/app
# ํ๋ก์ ์ฌ์ด๋์นด (Envoy)
- name: envoy-proxy
image: envoyproxy/envoy:v1.28
ports:
- containerPort: 9901
volumes:
- name: app-logs
emptyDir: {}์ฌ๋ฌ Job์ ์์๋๋ก ์คํํ๋ ์ํฌํ๋ก์ฐ ํจํด์ด์ผ. ๊ฐ Job์ด ์๋ฃ๋๋ฉด ๋ค์ Job์ ํธ๋ฆฌ๊ฑฐํด.
# 1๋จ๊ณ: ๋ฐ์ดํฐ ์ถ์ถ
apiVersion: batch/v1
kind: Job
metadata:
name: step1-extract
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: extractor
image: etl:1.0
command: ["python", "extract.py"]
---
# 2๋จ๊ณ: ๋ฐ์ดํฐ ๋ณํ (step1 ์๋ฃ ํ ์คํ)
apiVersion: batch/v1
kind: Job
metadata:
name: step2-transform
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: transformer
image: etl:1.0
command: ["python", "transform.py"]
---
# 3๋จ๊ณ: ๋ฐ์ดํฐ ๋ก๋ (step2 ์๋ฃ ํ ์คํ)
apiVersion: batch/v1
kind: Job
metadata:
name: step3-load
spec:
template:
spec:
restartPolicy: Never # ๋ฉฑ๋ฑ์ฑ ์๋ ์์
containers:
- name: loader
image: etl:1.0
command: ["python", "load.py"]restartPolicy + Liveness Probe + PodDisruptionBudget์ ์กฐํฉํด์ ์ง์ ํ ์๊ฐ ์น์ ์์คํ ์ ๋ง๋ค ์ ์์ด.
---
# 1. Deployment: ํญ์ 3๊ฐ ๋ ํ๋ฆฌ์นด ์ ์ง
apiVersion: apps/v1
kind: Deployment
metadata:
name: resilient-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
restartPolicy: Always
containers:
- name: app
image: my-app:1.0
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
---
# 2. PodDisruptionBudget: ์ต์ 2๊ฐ ํญ์ ์ ์ง
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: resilient-app-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: resilient-app
---
# 3. HorizontalPodAutoscaler: ๋ถํ์ ๋ฐ๋ผ ์๋ ์ค์ผ์ผ
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: resilient-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: resilient-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70restartPolicy๋ฅผ ์ ์ค์ ํ๋ค๊ณ ํด๋, ์ค์ ๋ก ์ผ๋ง๋ ์ฌ์์์ด ๋ฐ์ํ๋์ง ๋ชจ๋ํฐ๋งํ๋ ๊ฒ ์ค์ํด. Prometheus + Grafana ์กฐํฉ์ผ๋ก ์ด๋ฅผ ์ถ์ ํ ์ ์์ด.
# Prometheus ์ฟผ๋ฆฌ: Pod ์ฌ์์ ํ์
kube_pod_container_status_restarts_total
# ํน์ ๋ค์์คํ์ด์ค์ ์ฌ์์ ํ์
kube_pod_container_status_restarts_total{namespace="production"}
# ์ง๋ 1์๊ฐ ๋์ ์ฌ์์ ํ์ ์ฆ๊ฐ
increase(kube_pod_container_status_restarts_total[1h])
# ์ฌ์์ ํ์๊ฐ 5 ์ด์์ธ Pod ์๋ฆผ
kube_pod_container_status_restarts_total > 5# Prometheus AlertManager ๊ท์น ์์
groups:
- name: pod-restart-alerts
rules:
- alert: PodCrashLooping
expr: |
increase(kube_pod_container_status_restarts_total[15m]) > 3
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.pod }} ํฌ๋์ ๋ฃจํ ๊ฐ์ง"
description: "{{ $labels.namespace }}/{{ $labels.pod }}์ {{ $labels.container }} ์ปจํ
์ด๋๊ฐ 15๋ถ ๋ด 3๋ฒ ์ด์ ์ฌ์์๋จ"
- alert: PodFrequentlyRestarting
expr: |
kube_pod_container_status_restarts_total > 10
for: 1m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} ๋น๋ฒํ ์ฌ์์"
description: "์ด ์ฌ์์ ํ์: {{ $value }}"# ๋ชจ๋ Pod์ ์ฌ์์ ํ์ ํ์ธ
kubectl get pods --all-namespaces | sort -k5 -rn
# ์ฌ์์ ํ์๊ฐ ๋ง์ Pod ์ฐพ๊ธฐ
kubectl get pods -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,NAME:.metadata.name,RESTARTS:.status.containerStatuses[0].restartCount' \
| sort -k3 -rn | head -20
# ํน์ Pod์ ์์ธ ์ฌ์์ ์ ๋ณด
kubectl get pod my-pod -o jsonpath='{.status.containerStatuses[*].restartCount}'
# ์ฌ์์ ์ค์ธ Pod๋ง ํํฐ๋ง
kubectl get pods -A --field-selector=status.phase=Running | grep -v "0/\|1/1\|2/2\|3/3"์, ์ด์ restartPolicy์ ๋ํด ๊ฝค ๊น์ด ํ๋ดค์ด! ๋ง์ง๋ง์ผ๋ก ํต์ฌ ํฌ์ธํธ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ.
- 1 ๊ธฐ๋ณธ๊ฐ์ Always - ๋ช ์ํ์ง ์์ผ๋ฉด Always๊ฐ ์ ์ฉ๋จ
- 2 Pod ๋ ๋ฒจ ์ค์ - ๋ชจ๋ ์ปจํ ์ด๋์ ๋์ผํ๊ฒ ์ ์ฉ๋จ
- 3 Deployment/StatefulSet/DaemonSet - Always๋ง ์ฌ์ฉ ๊ฐ๋ฅ
- 4 Job/CronJob - OnFailure ๋๋ Never๋ง ์ฌ์ฉ ๊ฐ๋ฅ
- 5 ์ง์ ๋ฐฑ์คํ - ์ฌ์์ ๊ฐ๊ฒฉ์ด 10์ด โ 20์ด โ 40์ด... ์ต๋ 5๋ถ
- 6 ๋ฐฑ์คํ ๋ฆฌ์ - 10๋ถ ์ด์ ์ ์ ์คํ ์ ์นด์ดํฐ ๋ฆฌ์
- 7 ๋ฉฑ๋ฑ์ฑ ๊ณ ๋ ค - ์ค๋ณต ์คํ ๊ฐ๋ฅํ ์์ ๋ง OnFailure ์ฌ์ฉ
- 8 Liveness Probe ์กฐํฉ - ๋ฐ๋๋ฝ ๊ฐ์ง + ์๋ ์ฌ์์์ผ๋ก ์๊ฐ ์น์ ๊ตฌํ
์ฟ ๋ฒ๋คํฐ์ค์ restartPolicy๋ ๋จ์ํด ๋ณด์ด์ง๋ง, ์ค์ ๋ก๋ ์์คํ ์ ์์ ์ฑ๊ณผ ์ด์ ํจ์จ์ฑ์ ํฐ ์ํฅ์ ๋ฏธ์น๋ ์ค์ํ ์ค์ ์ด์ผ. ์ด ๊ธ์์ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๊ฐ ์ํฉ์ ๋ง๋ ์ ์ฑ ์ ์ ํํ๋ฉด, ํจ์ฌ ๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ์ฟ ๋ฒ๋คํฐ์ค ์ด์์ด ๊ฐ๋ฅํด์ง ๊ฑฐ์ผ! ๐ช
DevOps ๊ด๋ จ ์ง์์ ๋ ์๊ณ ์ถ๋ค๋ฉด ์ฌ๋ฅ๋ท์ ์ง์์ธ์ ์ฒ์์ ๋ค์ํ ์ ๋ฌธ๊ฐ๋ค์ ๊ธ์ ์ฐพ์๋ณผ ์ ์์ด. ์ฟ ๋ฒ๋คํฐ์ค๋ฟ๋ง ์๋๋ผ CI/CD, ํด๋ผ์ฐ๋ ์ํคํ ์ฒ, ์ธํ๋ผ ์๋ํ ๋ฑ ๋ค์ํ DevOps ์ฃผ์ ์ ์์ง์ ์ฝํ ์ธ ๋ค์ด ๊ฐ๋ํ๊ฑฐ๋ !
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.