쿠버네티스 코어 오브젝트 (Pods, ReplicaSets, Deployments, StatefulSets, Services, Ingress, ConfigMaps, Secrets, PVC, Jobs, DaemonSets)
1. Pod: 쿠버네티스의 기본 실행 단위
Pod의 역할
Pod는 쿠버네티스에서 가장 작은 배포 단위다. 하나 이상의 컨테이너를 묶어서 하나의 실행 환경을 만든다.
Pod가 하는 일:
- 컨테이너들이 같은 IP 주소를 공유하게 함
- 컨테이너들이 같은 저장공간을 사용할 수 있게 함
- 컨테이너들의 생명주기를 함께 관리
Pod 내부 구조
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
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
containers:
- name: web-server
image: nginx:1.21
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: content-updater
image: busybox
command: [ 'sh', '-c' ]
args:
- while true; do
echo "$(date): Hello from sidecar" > /shared/index.html;
sleep 30;
done
volumeMounts:
- name: shared-data
mountPath: /shared
volumes:
- name: shared-data
emptyDir: { }
Pod 생명주기 과정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌─────────────────────────────────────────────────────────────┐
│ Pod Lifecycle │
├─────────────────────────────────────────────────────────────┤
│ │
│ Pending → Running → Succeeded/Failed │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────┐ ┌─────┐ ┌─────────┐ │
│ │스케줄│ │컨테이│ │파드 완료│ │
│ │링 중│ │너실행│ │또는실패│ │
│ └─────┘ └─────┘ └─────────┘ │
│ │
│ 상태 확인 포인트: │
│ • PodScheduled: 노드에 스케줄링 완료 │
│ • Initialized: 모든 Init 컨테이너 완료 │
│ • ContainersReady: 모든 컨테이너 준비 완료 │
│ • Ready: Pod이 트래픽 수신 준비 완료 │
└─────────────────────────────────────────────────────────────┘
2. ReplicaSet: Pod 복사본 관리자
ReplicaSet의 역할
ReplicaSet은 지정된 수의 Pod가 항상 실행되도록 보장한다. Control Loop 패턴을 사용해 원하는 상태를 계속 유지한다.
ReplicaSet이 하는 일:
- Pod가 죽으면 새로 만들어서 교체
- 너무 많은 Pod가 있으면 여분을 제거
- 라벨 셀렉터로 관리할 Pod들을 찾아냄
ReplicaSet 설정
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
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-replicaset
spec:
replicas: 3
selector:
matchLabels:
app: nginx
matchExpressions:
- key: tier
operator: In
values: [ "frontend" ]
template:
metadata:
labels:
app: nginx
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.21
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
ReplicaSet Controller의 Reconciliation 과정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────┐
│ ReplicaSet Reconciliation │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 현재 상태 확인 │
│ ├── 실행 중인 파드 수 계산 │
│ ├── 라벨 셀렉터로 파드 필터링 │
│ └── 파드 상태 검증 (Running, Pending, Failed) │
│ │
│ 2. 원하는 상태와 비교 │
│ ├── Desired Replicas: 3 │
│ ├── Current Replicas: 2 │
│ └── Diff: +1 (파드 1개 추가 필요) │
│ │
│ 3. 조정 작업 수행 │
│ ├── 부족한 경우: 새 파드 생성 │
│ ├── 초과한 경우: 가장 오래된 파드 삭제 │
│ └── 실패한 파드: 새로운 파드로 교체 │
│ │
│ 4. 상태 업데이트 │
│ ├── ReplicaSet Status 업데이트 │
│ ├── 이벤트 생성 및 로그 기록 │
│ └── 다음 Reconciliation 주기 대기 │
└─────────────────────────────────────────────────────────────┘
3. Deployment: 애플리케이션 배포 관리자
Deployment의 역할
Deployment는 애플리케이션의 배포와 업데이트를 관리한다. ReplicaSet을 관리하는 상위 개념으로, 무중단 배포와 롤백 기능을 제공한다.
Deployment가 하는 일:
- 새 버전 배포 시 무중단 업데이트 (롤링 업데이트)
- 배포 이력 관리 및 롤백 기능 제공
- 배포 과정에서 문제 발생 시 자동 중단
Deployment 계층 구조
1
2
3
4
5
Deployment
↓ (관리)
ReplicaSet (v1) ReplicaSet (v2)
↓ ↓
Pod Pod Pod Pod Pod Pod
Deployment 설정
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
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 동시에 중단 가능한 파드 수
maxSurge: 2 # 동시에 추가 생성 가능한 파드 수
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
롤링 업데이트 과정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────┐
│ Rolling Update Process │
├─────────────────────────────────────────────────────────────┤
│ │
│ 초기 상태: nginx:1.20 (5개 파드) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ v20 │ │ v20 │ │ v20 │ │ v20 │ │ v20 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ 1단계: 새 ReplicaSet 생성 및 파드 2개 추가 (maxSurge=2) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ v20 │ │ v20 │ │ v20 │ │ v20 │ │ v20 │ │ v21 │ │ v21 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ 2단계: 새 파드 Ready 확인 후 기존 파드 1개 제거 │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ v20 │ │ v20 │ │ v20 │ │ v20 │ │ v21 │ │ v21 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ 3단계: 과정 반복하여 모든 파드 교체 완료 │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ v21 │ │ v21 │ │ v21 │ │ v21 │ │ v21 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
└─────────────────────────────────────────────────────────────┘
4. StatefulSet: 상태가 있는 애플리케이션 관리자
StatefulSet의 역할
StatefulSet은 데이터베이스나 분산 시스템 같은 상태가 있는 애플리케이션을 관리한다. 각 Pod가 고유한 신원을 가져야 하는 경우에 사용한다.
StatefulSet이 Deployment와 다른 점:
- Pod에 고정된 이름 부여 (web-0, web-1, web-2)
- Pod마다 전용 저장공간 제공 (PVC 자동 생성)
- 순서대로 생성/삭제/업데이트
- 안정적인 네트워크 식별자 제공
StatefulSet vs Deployment 비교
특성 | Deployment | StatefulSet |
---|---|---|
파드 이름 | 무작위 | 순차적 (web-0, web-1, web-2) |
네트워크 ID | 임시적 | 안정적 (web-0.service.ns.svc.cluster.local) |
스토리지 | 공유 가능 | 파드별 전용 PVC |
배포 순서 | 병렬 | 순차적 |
업데이트 | 롤링 (무작위) | 순차적 (역순) |
StatefulSet 설정
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
32
33
34
35
36
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-cluster
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-storage
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
StatefulSet 배포 과정
1
2
3
4
5
6
7
8
9
10
순차적 배포:
mysql-0 → Ready → mysql-1 → Ready → mysql-2
역순 업데이트:
mysql-2 업데이트 → mysql-1 업데이트 → mysql-0 업데이트
안정적 네트워크 식별자:
mysql-0.mysql.default.svc.cluster.local
mysql-1.mysql.default.svc.cluster.local
mysql-2.mysql.default.svc.cluster.local
5. Service: 네트워크 연결 관리자
Service의 역할
Service는 Pod들에 대한 안정적인 네트워크 접근 방법을 제공한다. Pod의 IP가 계속 바뀌는 문제를 해결하고, 로드밸런싱 기능도 제공한다.
Service가 필요한 이유:
- Pod는 죽었다 살아나면서 IP가 계속 바뀜
- 여러 Pod 중 어느 것에 요청을 보내야 할지 모름
- Service가 이런 문제를 해결하고 로드밸런싱도 제공
Service 타입별 역할과 설정
1. ClusterIP (기본값) - 클러스터 내부 전용
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 8080
2. NodePort - 외부 접근 가능
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 31000 # 30000-32767 범위
3. LoadBalancer - 클라우드 로드밸런서 자동 생성
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: web-loadbalancer
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080
6. Ingress: HTTP/HTTPS 라우팅 관리자
Ingress의 역할
Ingress는 클러스터 외부에서 HTTP/HTTPS로 들어오는 트래픽을 관리한다. 하나의 진입점에서 여러 서비스로 라우팅하는 역할을 한다.
Ingress가 하는 일:
- 도메인별로 다른 서비스로 라우팅
- URL 경로별로 다른 서비스로 분기
- SSL/TLS 인증서 관리
- 로드밸런싱과 트래픽 제어
Ingress 설정
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
32
33
34
35
36
37
38
39
40
41
42
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
tls:
- hosts:
- api.example.com
- web.example.com
secretName: example-tls
rules:
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1-service
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-v2-service
port:
number: 80
Ingress 라우팅 과정
1
2
3
4
5
외부 요청 → Ingress Controller → Service → Pod
web.example.com/ → web-service → web Pod
api.example.com/v1/ → api-v1-service → API v1 Pod
api.example.com/v2/ → api-v2-service → API v2 Pod
7. ConfigMap: 설정 데이터 관리자
ConfigMap의 역할
ConfigMap은 애플리케이션의 설정 정보를 코드와 분리하여 저장한다. 환경에 따라 다른 설정을 적용할 때 유용하다.
ConfigMap이 하는 일:
- 환경변수로 설정값 전달
- 설정 파일을 볼륨으로 마운트
- 코드 수정 없이 설정 변경 가능
ConfigMap 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# 키-값 쌍
database_url: "postgres://db:5432/myapp"
log_level: "info"
feature_flags: "feature1=true,feature2=false"
# 파일 형태
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
}
ConfigMap 사용 방법
환경변수로 주입:
1
2
3
4
5
6
7
8
9
10
11
12
spec:
containers:
- name: app
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
envFrom:
- configMapRef:
name: app-config
볼륨 마운트:
1
2
3
4
5
6
7
8
9
10
spec:
containers:
- name: app
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
8. Secret: 민감한 정보 관리자
Secret의 역할
Secret은 비밀번호, API 키, 인증서 같은 민감한 정보를 안전하게 저장한다. ConfigMap과 유사하지만 보안이 강화된 버전이다.
Secret과 ConfigMap의 차이:
- Secret: 민감한 정보 (Base64 인코딩, 암호화 가능)
- ConfigMap: 일반 설정 정보 (평문)
Secret 설정
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
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
# Base64로 인코딩된 값
database-password: cGFzc3dvcmQxMjM=
api-key: YWJjZGVmZ2hpams=
stringData:
# 평문으로 입력 (자동으로 Base64 인코딩됨)
smtp-password: "my-secret-password"
---
# Docker Registry 인증용 Secret
apiVersion: v1
kind: Secret
metadata:
name: docker-registry-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: |
{
"auths": {
"registry.example.com": {
"username": "user",
"password": "pass",
"auth": "dXNlcjpwYXNz"
}
}
}
Secret 사용 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spec:
containers:
- name: app
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: database-password
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secrets
defaultMode: 0400 # 읽기 전용
9. PersistentVolumeClaim: 저장공간 요청서
PVC의 역할
PVC는 Pod가 사용할 영구 저장공간을 요청한다. Pod가 재시작되거나 다른 노드로 이동해도 데이터가 보존된다.
PVC가 하는 일:
- 필요한 저장공간 크기와 성능 특성을 명시
- 스토리지 클래스에 따라 적절한 볼륨 할당
- Pod 생명주기와 독립적으로 데이터 보존
PVC 설정
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
# 고성능 SSD 스토리지
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: database-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
---
# 대용량 표준 스토리지
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: logs-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: standard
resources:
requests:
storage: 1Ti
Volume Access Modes
Mode | 설명 | 적합한 용도 |
---|---|---|
ReadWriteOnce (RWO) | 단일 노드에서 읽기/쓰기 | 데이터베이스, 단일 인스턴스 앱 |
ReadOnlyMany (ROX) | 여러 노드에서 읽기 전용 | 정적 컨텐츠, 공유 설정 |
ReadWriteMany (RWX) | 여러 노드에서 읽기/쓰기 | 공유 파일 시스템, 로그 수집 |
10. Job: 일회성 작업 관리자
Job의 역할
Job은 한 번 실행하고 끝나는 작업을 관리한다. 웹 서버처럼 계속 실행되는 서비스와 달리, 특정 작업을 완료하면 종료한다.
Job이 하는 일:
- 작업 완료까지 Pod 실행 유지
- 실패 시 자동 재시도
- 여러 작업을 병렬로 실행 가능
- 작업 완료 후 Pod 정리
Job 설정
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
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
# 완료할 작업 수
completions: 5
# 동시 실행할 파드 수
parallelism: 2
# 재시도 횟수
backoffLimit: 3
# 작업 완료 후 파드 유지 시간
ttlSecondsAfterFinished: 3600
template:
spec:
restartPolicy: Never
containers:
- name: migrator
image: migration:latest
command:
- /bin/sh
- -c
- |
echo "Starting migration batch ${JOB_COMPLETION_INDEX}"
migrate --batch=${JOB_COMPLETION_INDEX}
Job 실행 과정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────┐
│ Job Execution Process │
├─────────────────────────────────────────────────────────────┤
│ │
│ 목표: 5개 작업 완료, 최대 2개 병렬 실행 │
│ │
│ 1단계: Pod 2개 동시 시작 │
│ ┌───────────┐ ┌───────────┐ │
│ │ Task 1 │ │ Task 2 │ │
│ │ Running │ │ Running │ │
│ └───────────┘ └───────────┘ │
│ │
│ 2단계: Task 1 완료, Task 3 시작 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Task 1 │ │ Task 2 │ │ Task 3 │ │
│ │Completed │ │ Running │ │ Running │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
│ 3단계: 모든 작업 완료까지 반복 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Task 1-5 │ │ All │ │ Complete │ │ Job │ │ Finished │ │
│ │Completed │ │Completed │ │ Tasks │ │ Status │ │ Clean │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
11. CronJob: 정기 작업 관리자
CronJob의 역할
CronJob은 정해진 시간에 반복적으로 실행되는 작업을 관리한다. 리눅스의 cron과 같은 기능을 제공한다.
CronJob이 하는 일:
- 정해진 스케줄에 따라 Job 자동 생성
- 백업, 로그 정리, 리포트 생성 등에 활용
- 작업 이력 관리 및 실패 시 알림
CronJob 설정
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
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
spec:
# 매일 새벽 2시에 실행
schedule: "0 2 * * *"
# 동시 실행 정책
concurrencyPolicy: Forbid
# 실패한 작업 보관 수
failedJobsHistoryLimit: 3
# 성공한 작업 보관 수
successfulJobsHistoryLimit: 1
# 시작 기한 (초)
startingDeadlineSeconds: 300
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: postgres:13
command:
- /bin/bash
- -c
- |
BACKUP_FILE="/backup/db_$(date +%Y%m%d_%H%M%S).sql"
pg_dump $DATABASE_URL > $BACKUP_FILE
aws s3 cp $BACKUP_FILE s3://backup-bucket/database/
rm $BACKUP_FILE
CronJob 스케줄 예시
1
2
3
4
5
"0 2 * * *" # 매일 새벽 2시
"0 */6 * * *" # 6시간마다
"0 0 * * 0" # 매주 일요일 자정
"0 0 1 * *" # 매월 1일 자정
"0 9-17 * * 1-5" # 평일 오전 9시부터 오후 5시까지 매시간
12. DaemonSet: 노드별 필수 서비스 관리자
DaemonSet의 역할
DaemonSet은 모든 노드(또는 특정 노드)에서 반드시 실행되어야 하는 시스템 레벨 서비스를 관리한다.
DaemonSet이 하는 일:
- 새 노드가 클러스터에 추가되면 자동으로 Pod 배치
- 노드가 제거되면 해당 Pod도 함께 제거
- 시스템 모니터링, 로그 수집, 네트워킹 등에 주로 사용
- 각 노드마다 정확히 하나의 Pod만 실행
DaemonSet 설정
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
namespace: kube-system
spec:
selector:
matchLabels:
name: log-collector
template:
metadata:
labels:
name: log-collector
spec:
# 시스템 권한 필요
serviceAccountName: log-collector
hostNetwork: true
hostPID: true
containers:
- name: fluentd
image: fluentd:v1.14
resources:
limits:
memory: 512Mi
cpu: 100m
volumeMounts:
# 호스트의 로그 디렉토리 마운트
- name: varlog
mountPath: /var/log
readOnly: true
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
# Fluentd 설정
- name: config
mountPath: /fluentd/etc
env:
- name: ELASTICSEARCH_HOST
value: "elasticsearch.logging.svc.cluster.local"
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
- name: config
configMap:
name: fluentd-config
# 특정 노드에만 배포 (선택사항)
nodeSelector:
node-type: worker
# 노드 장애 시 빠른 재배포
tolerations:
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
tolerationSeconds: 30
DaemonSet 배포 과정
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
┌─────────────────────────────────────────────────────────────┐
│ DaemonSet Deployment Process │
├─────────────────────────────────────────────────────────────┤
│ │
│ 클러스터 상태: 3개 노드 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node-1 │ │ Node-2 │ │ Node-3 │ │
│ │ │ │ │ │ │ │
│ │ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │ │
│ │ │ Log │ │ │ │ Log │ │ │ │ Log │ │ │
│ │ │ Pod │ │ │ │ Pod │ │ │ │ Pod │ │ │
│ │ └─────┘ │ │ └─────┘ │ │ └─────┘ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 새 노드 추가 시: │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node-1 │ │ Node-2 │ │ Node-3 │ │ Node-4 │ │
│ │ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │ │
│ │ │ Log │ │ │ │ Log │ │ │ │ Log │ │ │ │ Log │ │ │
│ │ │ Pod │ │ │ │ Pod │ │ │ │ Pod │ │ │ │ Pod │ │ │
│ │ └─────┘ │ │ └─────┘ │ │ └─────┘ │ │ └─────┘ │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ↑ │
│ 자동으로 Pod 생성 │
└─────────────────────────────────────────────────────────────┘
DaemonSet 주요 용도
- 로그 수집기: Fluentd, Filebeat, Logstash
- 모니터링 에이전트: Prometheus Node Exporter, Datadog Agent
- 네트워크 플러그인: Calico, Flannel, Weave
- 보안 에이전트: Falco, Twistlock
- 스토리지 드라이버: Ceph, GlusterFS
오브젝트 간의 관계와 전체 구조
계층적 관리 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Object Hierarchy │
├─────────────────────────────────────────────────────────────┤
│ │
│ 외부 접근 계층: │
│ Ingress → Service → Pod │
│ │
│ 워크로드 관리 계층: │
│ Deployment → ReplicaSet → Pod │
│ StatefulSet → Pod (+ PVC) │
│ DaemonSet → Pod (각 노드마다) │
│ Job/CronJob → Pod (임시) │
│ │
│ 설정 및 데이터 계층: │
│ Pod ← ConfigMap (설정) │
│ Pod ← Secret (민감정보) │
│ Pod ← PVC (영구저장소) │
└─────────────────────────────────────────────────────────────┘
실제 애플리케이션 예시
웹 애플리케이션 전체 구성:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# 1. 네임스페이스
apiVersion: v1
kind: Namespace
metadata:
name: webapp
---
# 2. 설정 관리
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: webapp
data:
database_host: "mysql-service"
redis_host: "redis-service"
---
# 3. 민감정보 관리
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: webapp
stringData:
db_password: "secret123"
api_key: "abcd1234"
---
# 4. 데이터베이스 (StatefulSet)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: webapp
spec:
serviceName: mysql-service
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db_password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 20Gi
---
# 5. 데이터베이스 서비스
apiVersion: v1
kind: Service
metadata:
name: mysql-service
namespace: webapp
spec:
clusterIP: None # Headless Service
selector:
app: mysql
ports:
- port: 3306
---
# 6. 웹 애플리케이션 (Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
namespace: webapp
spec:
replicas: 3
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: webapp:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database_host
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db_password
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
---
# 7. 웹 애플리케이션 서비스
apiVersion: v1
kind: Service
metadata:
name: webapp-service
namespace: webapp
spec:
selector:
app: webapp
ports:
- port: 80
targetPort: 8080
---
# 8. 외부 접근 (Ingress)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
namespace: webapp
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
---
# 9. 정기 백업 작업 (CronJob)
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
namespace: webapp
spec:
schedule: "0 2 * * *" # 매일 새벽 2시
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: mysql:8.0
command:
- /bin/bash
- -c
- mysqldump -h mysql-service -u root -p$MYSQL_ROOT_PASSWORD mydb > /backup/backup_$(date +%Y%m%d).sql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db_password
주요 Best Practices
1. 리소스 관리:
1
2
3
4
5
6
7
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
2. 헬스 체크:
1
2
3
4
5
6
7
8
9
10
11
12
13
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
3. 보안 설정:
1
2
3
4
5
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
4. 라벨링 전략:
1
2
3
4
5
6
metadata:
labels:
app: webapp
version: v1.2.0
environment: production
component: frontend