Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- 분산 시스템
- ApacheBench
- 세션저장소
- 프로덕션 운영
- kubernetes
- 메시지 브로커
- 인메모리데이터베이스
- CI/CD
- infrastructureascode
- 고가용성
- RabbitMQ Exchange
- 클라우드
- 마이크로서비스 운영
- 마이크로서비스
- 서비스 메시
- Python
- 클러스터
- 이벤트 스트리밍
- 컨테이너오케스트레이션
- rabbitmq
- 모니터링
- 마이크로서비스 통신
- 분산 모니터링
- 서비스 설계
- 보안
- docker
- 메시징 패턴
- Kafka 클러스터
- devops
- 모노리스 분해
Archives
- Today
- Total
hobokai 님의 블로그
Kubernetes 완전 정복 가이드: 컨테이너 오케스트레이션부터 프로덕션까지 본문
목차
- Kubernetes란 무엇인가?
- Kubernetes 아키텍처
- 설치 및 환경 구성
- 핵심 개념과 오브젝트
- Pod와 컨테이너 관리
- Service와 네트워킹
- 볼륨과 스토리지
- ConfigMap과 Secret
- 배포 전략과 관리
- Ingress와 로드밸런싱
- 오토스케일링
- Helm 패키지 관리
- 모니터링과 로깅
- 보안
- 운영 베스트 프랙티스
- 결론
Kubernetes란 무엇인가?
Kubernetes(K8s)는 Google이 개발하고 2014년 오픈소스로 공개한 컨테이너 오케스트레이션 플랫폼입니다. 컨테이너화된 애플리케이션의 배포, 관리, 확장을 자동화하는 시스템입니다.
Kubernetes의 핵심 가치
- 🚀 자동화 - 배포, 확장, 복구 자동화
- 🔄 자가 치유 - 실패한 컨테이너 자동 재시작
- 📈 확장성 - 수평/수직 스케일링 지원
- ⚡ 고가용성 - 다중 노드 클러스터로 무중단 서비스
- 🌍 포터빌리티 - 클라우드 독립적 운영
- 📦 선언적 구성 - 원하는 상태 정의로 관리
Kubernetes가 해결하는 문제들
| 문제 | Docker만 사용 | Kubernetes 해결 |
|---|---|---|
| 다중 호스트 관리 | 수동 관리 | 자동 스케줄링 |
| 로드 밸런싱 | 외부 도구 필요 | 내장 Service |
| 서비스 디스커버리 | 수동 설정 | 자동 DNS |
| 롤링 업데이트 | 스크립트 필요 | 내장 기능 |
| 자동 복구 | 모니터링 도구 | 자가 치유 |
| 구성 관리 | 환경별 설정 | ConfigMap/Secret |
Docker Swarm vs Kubernetes 비교
| 특성 | Docker Swarm | Kubernetes |
|---|---|---|
| 설정 복잡도 | 낮음 | 높음 |
| 기능 풍부도 | 기본적 | 매우 풍부 |
| 커뮤니티 | 작음 | 매우 큼 |
| 학습 곡선 | 완만함 | 가파름 |
| 생태계 | 제한적 | 광범위함 |
| 기업 지원 | Docker Inc. | CNCF 전체 |
Kubernetes 아키텍처
클러스터 구성 요소
┌─────────────────────────────────────────────────────────────┐
│ Master Node │
├─────────────────────────────────────────────────────────────┤
│ API Server │ etcd │ Scheduler │ Controller Manager │
└─────────────────────────────────────────────────────────────┘
│
│ (API 통신)
│
┌─────────────────────────────────────────────────────────────┐
│ Worker Nodes │
├─────────────────────────────────────────────────────────────┤
│ kubelet │ kube-proxy │ Container Runtime (Docker/CRI) │
│ │ │
│ ┌─────────────────────┐ │ ┌─────────────────────────────┐ │
│ │ Pod 1 │ │ │ Pod 2 │ │
│ │ ┌─────┐ ┌─────────┐│ │ │ ┌─────────┐ ┌─────────────┐│ │
│ │ │App A│ │ Sidecar ││ │ │ │ App B │ │ App C ││ │
│ │ └─────┘ └─────────┘│ │ │ └─────────┘ └─────────────┘│ │
│ └─────────────────────┘ │ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘Master Node (Control Plane) 구성 요소
1. API Server (kube-apiserver)
- 클러스터의 게이트웨이
- 모든 REST API 요청 처리
- 인증, 인가, admission control
- etcd와의 유일한 통신 창구
2. etcd
- 분산 키-값 저장소
- 클러스터의 모든 상태 정보 저장
- 백업과 복원의 핵심 구성 요소
3. Scheduler (kube-scheduler)
- Pod를 적절한 Node에 배치
- 리소스 요구사항, 제약사항 고려
- 커스텀 스케줄링 정책 지원
4. Controller Manager (kube-controller-manager)
- 원하는 상태 유지 담당
- ReplicaSet, Deployment, Service 등 관리
- 지속적인 reconciliation loop 실행
Worker Node 구성 요소
1. kubelet
- 각 노드의 Kubernetes 에이전트
- Pod 생명주기 관리
- Master와의 통신 담당
2. kube-proxy
- 네트워크 프록시 역할
- Service와 Endpoint 관리
- iptables/IPVS 룰 관리
3. Container Runtime
- 컨테이너 실행 환경
- Docker, containerd, CRI-O 등
설치 및 환경 구성
로컬 개발 환경
1. minikube 설치
# macOS
brew install minikube
# Windows (Chocolatey)
choco install minikube
# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# 클러스터 시작
minikube start --driver=docker
minikube start --cpus=4 --memory=8192 # 리소스 지정
# 상태 확인
minikube status
minikube dashboard # 웹 UI 열기
2. Kind (Kubernetes in Docker)
# Kind 설치
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# 클러스터 생성
kind create cluster --name my-cluster
kind create cluster --config=kind-config.yaml
# 다중 노드 클러스터 설정
cat << EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
kind create cluster --config=kind-config.yaml
3. Docker Desktop Kubernetes
# Docker Desktop 설정에서 Kubernetes 활성화
# Settings > Kubernetes > Enable Kubernetes
# 컨텍스트 확인
kubectl config get-contexts
kubectl config use-context docker-desktop
kubectl 설치 및 설정
# kubectl 설치
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# 자동 완성 설정
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
# 클러스터 연결 확인
kubectl cluster-info
kubectl get nodes
kubectl version --client --output=yaml
프로덕션 클러스터 구축
kubeadm을 이용한 클러스터 구축
# 모든 노드에서 Docker와 kubelet 설치
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
# Kubernetes 레포지토리 추가
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# kubelet, kubeadm, kubectl 설치
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# Master 노드 초기화
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
# kubectl 설정
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 네트워크 애드온 설치 (Flannel)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# Worker 노드 조인
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash <hash>
핵심 개념과 오브젝트
Kubernetes 오브젝트 계층 구조
Namespace
├── Pod (기본 실행 단위)
│ └── Container(s)
├── ReplicaSet (Pod 복제 관리)
├── Deployment (애플리케이션 배포)
├── Service (네트워크 접근)
├── ConfigMap (설정 데이터)
├── Secret (민감한 데이터)
├── PersistentVolume (스토리지)
└── Ingress (외부 접근)네임스페이스
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: prod
---
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: dev
# 네임스페이스 관리
kubectl create namespace my-app
kubectl get namespaces
kubectl config set-context --current --namespace=my-app
# 네임스페이스별 리소스 확인
kubectl get pods -n production
kubectl get all -A # 모든 네임스페이스
라벨과 셀렉터
# 라벨 사용 예시
apiVersion: v1
kind: Pod
metadata:
name: web-app
labels:
app: web
version: v1.0
environment: production
tier: frontend
spec:
containers:
- name: web
image: nginx:1.20
# 라벨 기반 검색
kubectl get pods -l app=web
kubectl get pods -l environment=production,tier=frontend
kubectl get pods -l 'version in (v1.0, v1.1)'
# 라벨 수정
kubectl label pod web-app version=v1.1 --overwrite
kubectl label pod web-app tier- # 라벨 삭제
Pod와 컨테이너 관리
Pod 기본 개념
Pod는 Kubernetes의 최소 배포 단위입니다. 하나 이상의 컨테이너를 포함하며, 같은 Pod 내 컨테이너들은 네트워크와 스토리지를 공유합니다.
단일 컨테이너 Pod
# simple-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
env:
- name: ENV
value: "production"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
다중 컨테이너 Pod (사이드카 패턴)
# multi-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-with-logging
spec:
volumes:
- name: shared-logs
emptyDir: {}
containers:
# 메인 애플리케이션 컨테이너
- name: web-app
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
# 로그 수집 사이드카 컨테이너
- name: log-shipper
image: fluent/fluent-bit:1.8
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
env:
- name: FLUENTD_CONF
value: "fluent-bit.conf"
Pod 생명주기와 상태
# Pod 생성 및 관리
kubectl create -f pod.yaml
kubectl apply -f pod.yaml
# Pod 상태 확인
kubectl get pods
kubectl get pods -o wide # 더 많은 정보
kubectl describe pod nginx-pod
# Pod 로그 확인
kubectl logs nginx-pod
kubectl logs nginx-pod -c container-name # 다중 컨테이너
kubectl logs -f nginx-pod # 실시간 로그
# Pod 실행 명령
kubectl exec nginx-pod -- ls -la
kubectl exec -it nginx-pod -- bash
# Pod 삭제
kubectl delete pod nginx-pod
kubectl delete -f pod.yaml
Init 컨테이너
# init-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
Service와 네트워킹
Service 타입별 특징
| Service 타입 | 용도 | 접근 방법 |
|---|---|---|
| ClusterIP | 내부 통신 | 클러스터 내부에서만 |
| NodePort | 외부 노출 | 노드IP:포트 |
| LoadBalancer | 클라우드 LB | 외부 로드밸런서 |
| ExternalName | 외부 서비스 | DNS CNAME |
ClusterIP Service (내부 통신)
# clusterip-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: ClusterIP # 기본값
selector:
app: my-app
ports:
- port: 80 # 서비스 포트
targetPort: 8080 # 컨테이너 포트
protocol: TCP
name: http
NodePort Service (외부 노출)
# nodeport-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-nodeport
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 30000-32767 범위
LoadBalancer Service (클라우드)
# loadbalancer-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-lb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb" # AWS NLB
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
Headless Service (StatefulSet용)
# headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-stateful-service
spec:
clusterIP: None # Headless 설정
selector:
app: my-stateful-app
ports:
- port: 80
targetPort: 8080
서비스 디스커버리와 DNS
# 서비스 확인
kubectl get services
kubectl describe service my-app-service
# DNS 확인 (Pod 내부에서)
nslookup my-app-service
nslookup my-app-service.default.svc.cluster.local
# Endpoint 확인
kubectl get endpoints my-app-service
완전한 애플리케이션 예시
# web-app-complete.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: web-app-service
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 80
type: LoadBalancer
볼륨과 스토리지
볼륨 타입별 특징
| 볼륨 타입 | 특징 | 사용 사례 |
|---|---|---|
| emptyDir | Pod 생명주기와 동일 | 임시 데이터 |
| hostPath | 노드 파일시스템 | 로깅, 모니터링 |
| persistentVolumeClaim | 영구 스토리지 | 데이터베이스 |
| configMap/secret | 설정 데이터 | 환경 설정 |
| nfs/cephfs | 네트워크 스토리지 | 공유 파일시스템 |
기본 볼륨 사용
# volume-examples.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: app
image: nginx:1.20
volumeMounts:
- name: html-volume
mountPath: /usr/share/nginx/html
- name: config-volume
mountPath: /etc/config
- name: cache-volume
mountPath: /tmp/cache
volumes:
# 빈 디렉토리 볼륨
- name: html-volume
emptyDir: {}
# ConfigMap 볼륨
- name: config-volume
configMap:
name: app-config
# 호스트 경로 볼륨
- name: cache-volume
hostPath:
path: /tmp/pod-cache
type: DirectoryOrCreate
PersistentVolume과 PersistentVolumeClaim
# persistent-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-storage
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
---
apiVersion: v1
kind: Pod
metadata:
name: pv-pod
spec:
containers:
- name: app
image: nginx:1.20
volumeMounts:
- name: storage
mountPath: /usr/share/nginx/html
volumes:
- name: storage
persistentVolumeClaim:
claimName: pvc-storage
StorageClass (동적 프로비저닝)
# storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
allowVolumeExpansion: true
reclaimPolicy: Delete
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: fast-ssd
스토리지 관리 명령어
# PV/PVC 확인
kubectl get pv
kubectl get pvc
kubectl describe pv pv-storage
# 스토리지 클래스 확인
kubectl get storageclass
kubectl describe storageclass fast-ssd
# 볼륨 사용량 확인
kubectl exec -it pod-name -- df -h
ConfigMap과 Secret
ConfigMap 생성 및 사용
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# 키-값 데이터
database_host: "postgres.example.com"
database_port: "5432"
log_level: "info"
# 파일 형태 데이터
app.properties: |
server.port=8080
server.host=0.0.0.0
logging.level=INFO
nginx.conf: |
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
ConfigMap 사용 방법들
# configmap-usage.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: app
image: nginx:1.20
# 환경 변수로 사용
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database_host
# 모든 키를 환경 변수로 사용
envFrom:
- configMapRef:
name: app-config
# 볼륨으로 마운트
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: nginx-config
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: app-config
- name: nginx-config
configMap:
name: app-config
items:
- key: nginx.conf
path: default.conf
Secret 생성 및 사용
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
# base64 인코딩된 데이터
username: YWRtaW4= # admin
password: MWYyZDFlMmU2N2Rm # 1f2d1e2e67df
stringData:
# 평문 데이터 (자동으로 base64 인코딩됨)
api-key: "super-secret-key"
database-url: "postgresql://user:pass@db:5432/mydb"
---
# TLS 시크릿
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # base64 encoded cert
tls.key: LS0tLS1CRUdJTi... # base64 encoded key
Secret 사용
# secret-usage.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
containers:
- name: app
image: nginx:1.20
# 환경 변수로 사용
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: app-secrets
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: password
# 볼륨으로 마운트
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secrets
defaultMode: 0400 # 읽기 전용
ConfigMap/Secret 관리 명령어
# ConfigMap 생성
kubectl create configmap app-config --from-literal=key1=value1 --from-literal=key2=value2
kubectl create configmap app-config --from-file=config.properties
kubectl create configmap app-config --from-env-file=.env
# Secret 생성
kubectl create secret generic app-secrets --from-literal=username=admin --from-literal=password=secret
kubectl create secret tls tls-secret --cert=tls.crt --key=tls.key
kubectl create secret docker-registry regcred --docker-server=registry.com --docker-username=user --docker-password=pass
# 확인
kubectl get configmap
kubectl get secret
kubectl describe configmap app-config
kubectl get secret app-secrets -o yaml
배포 전략과 관리
Deployment
Deployment는 애플리케이션의 선언적 업데이트를 제공하는 가장 중요한 오브젝트입니다.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 동시에 삭제 가능한 Pod 수
maxSurge: 1 # 동시에 생성 가능한 추가 Pod 수
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
version: v1.0
spec:
containers:
- name: web
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
ReplicaSet
# replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: web-replicaset
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.20
ports:
- containerPort: 80
StatefulSet
# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres-statefulset
spec:
serviceName: postgres-service
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:14
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
# 볼륨 템플릿 (각 Pod마다 개별 볼륨)
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
DaemonSet
# daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # 호스트 네트워크 사용
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
Job과 CronJob
# job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
completions: 1 # 성공적으로 완료되어야 하는 Pod 수
parallelism: 1 # 동시에 실행할 Pod 수
backoffLimit: 3 # 실패 허용 횟수
template:
spec:
containers:
- name: migration
image: my-app:latest
command: ["python", "migrate.py"]
restartPolicy: Never # Job에서는 Never 또는 OnFailure
---
# cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-cronjob
spec:
schedule: "0 2 * * *" # 매일 새벽 2시
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: backup-tool:latest
command:
- /bin/sh
- -c
- |
echo "Starting backup..."
pg_dump -h postgres -U user mydb > /backup/backup-$(date +%Y%m%d).sql
echo "Backup completed"
restartPolicy: OnFailure
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
배포 관리 명령어
# Deployment 관리
kubectl create deployment web --image=nginx:1.20
kubectl get deployments
kubectl describe deployment web
# 스케일링
kubectl scale deployment web --replicas=5
kubectl autoscale deployment web --min=2 --max=10 --cpu-percent=80
# 롤링 업데이트
kubectl set image deployment/web web=nginx:1.21
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web # 이전 버전으로 롤백
kubectl rollout undo deployment/web --to-revision=2 # 특정 버전으로 롤백
# 배포 일시 중지/재개
kubectl rollout pause deployment/web
kubectl rollout resume deployment/web
Ingress와 로드밸런싱
Ingress Controller 설치
# NGINX Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml
# Traefik Ingress Controller
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik traefik/traefik
# 설치 확인
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
기본 Ingress 설정
# basic-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
고급 Ingress 설정
# advanced-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: advanced-ingress
annotations:
# NGINX 특정 설정
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
nginx.ingress.kubernetes.io/rate-limit: "10"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
# 캐싱 설정
nginx.ingress.kubernetes.io/server-snippet: |
location ~* \.(js|css|png|jpg)$ {
expires 1y;
add_header Cache-Control "public";
}
spec:
ingressClassName: nginx
# TLS 설정
tls:
- hosts:
- myapp.example.com
- api.example.com
secretName: tls-secret
rules:
# 메인 앱
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# API 서버
- host: api.example.com
http:
paths:
- path: /api/v1
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /api/v2
pathType: Prefix
backend:
service:
name: api-v2-service
port:
number: 8080
# 경로 기반 라우팅
- host: services.example.com
http:
paths:
- path: /auth
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 3000
- path: /payment
pathType: Prefix
backend:
service:
name: payment-service
port:
number: 4000
완전한 웹 애플리케이션 예시
# complete-web-app.yaml
# Frontend Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: nginx:1.20
ports:
- containerPort: 80
---
# Frontend Service
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
---
# Backend Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: node:18-alpine
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: production
---
# Backend Service
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
ports:
- port: 3000
targetPort: 3000
---
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: myapp.local
http:
paths:
- path: /()(.*)
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 3000
오토스케일링
Horizontal Pod Autoscaler (HPA)
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-deployment
minReplicas: 2
maxReplicas: 20
metrics:
# CPU 사용률 기반
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 메모리 사용률 기반
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# 커스텀 메트릭 기반
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: "1k"
# 외부 메트릭 기반
- type: External
external:
metric:
name: pubsub.googleapis.com|subscription|num_undelivered_messages
selector:
matchLabels:
resource.labels.subscription_id: my-subscription
target:
type: AverageValue
averageValue: "30"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
Vertical Pod Autoscaler (VPA)
# vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-deployment
updatePolicy:
updateMode: "Auto" # Off, Initial, Auto
resourcePolicy:
containerPolicies:
- containerName: web
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
Cluster Autoscaler 설정
# cluster-autoscaler.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
spec:
containers:
- image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.21.0
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=aws
- --skip-nodes-with-local-storage=false
- --expander=least-waste
- --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster
- --balance-similar-node-groups
- --skip-nodes-with-system-pods=false
스케일링 관리 명령어
# HPA 생성 및 관리
kubectl autoscale deployment web-deployment --cpu-percent=50 --min=1 --max=10
kubectl get hpa
kubectl describe hpa web-hpa
# 메트릭 서버 설치 (필수)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 리소스 사용량 확인
kubectl top nodes
kubectl top pods
# VPA 설치
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler/
./hack/vpa-install.sh
Helm 패키지 관리
Helm 설치
# macOS
brew install helm
# Windows (Chocolatey)
choco install kubernetes-helm
# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 버전 확인
helm version
Helm 기본 사용법
# 레포지토리 관리
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm repo list
# 차트 검색
helm search repo nginx
helm search hub wordpress
# 차트 정보 확인
helm show chart bitnami/nginx
helm show values bitnami/nginx > nginx-values.yaml
Helm 차트 생성
# 새 차트 생성
helm create my-app
# 생성된 구조
my-app/
├── Chart.yaml # 차트 메타데이터
├── values.yaml # 기본 값들
├── charts/ # 의존성 차트들
├── templates/ # 쿠버네티스 매니페스트 템플릿
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl # 템플릿 헬퍼들
│ └── tests/
└── .helmignore
Chart.yaml 예시
# Chart.yaml
apiVersion: v2
name: my-web-app
description: A Helm chart for my web application
type: application
version: 0.1.0
appVersion: "1.0.0"
maintainers:
- name: Your Name
email: your-email@example.com
dependencies:
- name: postgresql
version: 11.9.13
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: 17.3.7
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
values.yaml 예시
# values.yaml
replicaCount: 2
image:
repository: nginx
tag: "1.20"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: true
className: "nginx"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
hosts:
- host: myapp.local
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.local
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
postgresql:
enabled: true
auth:
username: myapp
password: mypassword
database: myapp_db
redis:
enabled: true
auth:
password: redis-password
템플릿 예시
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
env:
{{- if .Values.postgresql.enabled }}
- name: DATABASE_URL
value: "postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ include "my-app.fullname" . }}-postgresql:5432/{{ .Values.postgresql.auth.database }}"
{{- end }}
{{- if .Values.redis.enabled }}
- name: REDIS_URL
value: "redis://:{{ .Values.redis.auth.password }}@{{ include "my-app.fullname" . }}-redis:6379"
{{- end }}
livenessProbe:
httpGet:
path: /health
port: http
readinessProbe:
httpGet:
path: /ready
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
Helm 배포 관리
# 차트 설치
helm install my-release ./my-app
helm install my-release ./my-app --values custom-values.yaml
helm install my-release ./my-app --set replicaCount=3 --set image.tag=v2.0
# 릴리스 관리
helm list
helm list --all-namespaces
helm status my-release
helm get values my-release
# 업그레이드
helm upgrade my-release ./my-app --values new-values.yaml
helm upgrade my-release ./my-app --reuse-values --set image.tag=v2.1
# 롤백
helm rollback my-release 1 # 버전 1로 롤백
helm history my-release
# 삭제
helm uninstall my-release
helm uninstall my-release --keep-history
# 차트 검증
helm lint ./my-app
helm template my-release ./my-app --debug
helm install --dry-run --debug my-release ./my-app
모니터링과 로깅
Prometheus + Grafana 스택
# Prometheus Operator 설치
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# kube-prometheus-stack 설치 (Prometheus + Grafana + Alertmanager)
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.retention=15d \
--set grafana.adminPassword=admin123
커스텀 ServiceMonitor
# service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics
path: /metrics
interval: 30s
애플리케이션 메트릭 노출
# app-with-metrics.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:latest
ports:
- name: http
containerPort: 8080
- name: metrics
containerPort: 9090
env:
- name: METRICS_PORT
value: "9090"
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
labels:
app: my-app
spec:
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
ELK 스택 (Elasticsearch, Logstash, Kibana)
# elk-stack.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: elasticsearch:8.5.0
env:
- name: discovery.type
value: single-node
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
- name: xpack.security.enabled
value: "false"
ports:
- containerPort: 9200
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: kibana:8.5.0
env:
- name: ELASTICSEARCH_HOSTS
value: http://elasticsearch:9200
ports:
- containerPort: 5601
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:2.0
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: elasticsearch
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluent-bit-config
mountPath: /fluent-bit/etc/
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluent-bit-config
configMap:
name: fluent-bit-config
로그 수집 설정
# fluent-bit-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
data:
fluent-bit.conf: |
[SERVICE]
Daemon Off
Flush 1
Log_Level info
Parsers_File parsers.conf
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser cri
Tag kube.*
Refresh_Interval 5
Mem_Buf_Limit 10MB
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
[OUTPUT]
Name es
Match *
Host elasticsearch
Port 9200
Index k8s-logs
Type _doc
parsers.conf: |
[PARSER]
Name cri
Format regex
Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L%z
보안
RBAC (Role-Based Access Control)
# rbac.yaml
# ServiceAccount 생성
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
---
# Role 생성 (네임스페이스 범위)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
# ClusterRole 생성 (클러스터 전체 범위)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
---
# RoleBinding 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: ServiceAccount
name: my-service-account
namespace: default
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
---
# ClusterRoleBinding 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-nodes
subjects:
- kind: ServiceAccount
name: my-service-account
namespace: default
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
Pod Security Standards
# pod-security.yaml
apiVersion: v1
kind: Namespace
metadata:
name: secure-namespace
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
# 보안이 강화된 Pod
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
namespace: secure-namespace
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.20
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
resources:
limits:
memory: "128Mi"
cpu: "500m"
requests:
memory: "64Mi"
cpu: "250m"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
NetworkPolicy
# network-policy.yaml
# 기본적으로 모든 트래픽 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 웹 앱에 대한 허용 정책
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: web-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
# DNS 허용
- to: []
ports:
- protocol: UDP
port: 53
# 데이터베이스 접근 허용
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
# 외부 API 허용
- to: []
ports:
- protocol: TCP
port: 443
이미지 보안 스캔
# admission-controller.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: image-policy
data:
policy.json: |
{
"imagePolicy": {
"rules": [
{
"resource": "pods",
"allowed": [
"registry.company.com/*",
"docker.io/library/*"
],
"denied": [
"*:latest"
]
}
]
}
}
운영 베스트 프랙티스
리소스 관리
# resource-management.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: development
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
persistentvolumeclaims: "4"
pods: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
namespace: development
spec:
limits:
- default:
memory: "512Mi"
cpu: "500m"
defaultRequest:
memory: "256Mi"
cpu: "250m"
type: Container
헬스 체크
# health-checks.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: robust-app
spec:
replicas: 3
selector:
matchLabels:
app: robust-app
template:
metadata:
labels:
app: robust-app
spec:
containers:
- name: app
image: my-app:latest
ports:
- containerPort: 8080
# 시작 프로브 - 컨테이너가 시작되었는지 확인
startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10
timeoutSeconds: 5
# 라이브니스 프로브 - 컨테이너가 살아있는지 확인
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 레디니스 프로브 - 트래픽을 받을 준비가 되었는지 확인
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
배포 전략
# deployment-strategies.yaml
# Blue-Green 배포용 Service
apiVersion: v1
kind: Service
metadata:
name: blue-green-service
spec:
selector:
app: my-app
version: blue # blue 또는 green으로 전환
ports:
- port: 80
targetPort: 8080
---
# Canary 배포용 설정
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: canary-rollout
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10 # 10% 트래픽
- pause:
duration: 10m # 10분 대기
- setWeight: 50 # 50% 트래픽
- pause:
duration: 5m # 5분 대기
- setWeight: 100 # 100% 트래픽
canaryService: canary-service
stableService: stable-service
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:latest
백업 및 재해 복구
# backup-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup
spec:
schedule: "0 2 * * *" # 매일 새벽 2시
jobTemplate:
spec:
template:
spec:
containers:
- name: etcd-backup
image: quay.io/coreos/etcd:latest
env:
- name: ETCDCTL_API
value: "3"
command:
- /bin/sh
- -c
- |
etcdctl --endpoints=https://etcd:2379 \
--cacert=/etc/ssl/etcd/ca.crt \
--cert=/etc/ssl/etcd/etcd.crt \
--key=/etc/ssl/etcd/etcd.key \
snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db
volumeMounts:
- name: backup-storage
mountPath: /backup
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure
클러스터 업그레이드 절차
# 1. 현재 버전 확인
kubectl version --short
# 2. 업그레이드 가능한 버전 확인
sudo apt update
sudo apt-cache madison kubeadm
# 3. kubeadm 업그레이드 (마스터 노드)
sudo apt-mark unhold kubeadm
sudo apt-get update
sudo apt-get install -y kubeadm=1.28.x-00
sudo apt-mark hold kubeadm
# 4. 업그레이드 계획 확인
sudo kubeadm upgrade plan
# 5. 마스터 노드 업그레이드
sudo kubeadm upgrade apply v1.28.x
# 6. kubelet과 kubectl 업그레이드
sudo apt-mark unhold kubelet kubectl
sudo apt-get update
sudo apt-get install -y kubelet=1.28.x-00 kubectl=1.28.x-00
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 7. 워커 노드 업그레이드 (각 노드에서)
kubectl drain worker-node --ignore-daemonsets
sudo kubeadm upgrade node
# kubelet, kubectl 업그레이드 (위와 동일)
kubectl uncordon worker-node
결론
Kubernetes는 현대 클라우드 네이티브 애플리케이션의 핵심 인프라입니다. 복잡하지만 체계적으로 학습하고 실습하면 강력한 컨테이너 오케스트레이션 플랫폼을 운영할 수 있습니다.
Kubernetes 마스터 로드맵
- 기초: Docker 기본, K8s 개념, Pod/Service 이해
- 중급: Deployment, ConfigMap, Ingress, 스토리지 관리
- 고급: RBAC, 네트워크 정책, 모니터링, Helm
- 전문가: 멀티 클러스터, 서비스 메시, GitOps, 운영 자동화
실무 적용 단계
- 로컬 환경: minikube/kind로 학습 환경 구축
- 개발 환경: 단순한 애플리케이션 배포
- 스테이징: 프로덕션과 유사한 환경 구축
- 프로덕션: 고가용성, 보안, 모니터링 완비
지속적 학습 리소스
- 📚 공식 문서: https://kubernetes.io/docs/
- 🎓 Kubernetes 인증: CKA, CKAD, CKS
- 🧪 실습 환경: https://killercoda.com/playgrounds
- 📖 추천 도서: "Kubernetes in Action", "Kubernetes Up & Running"
- 🏆 커뮤니티: CNCF, Kubernetes Slack
마지막 조언
- 실습 중심: 이론보다 직접 클러스터 운영 경험이 중요
- 점진적 적용: 한 번에 모든 기능을 도입하지 말고 단계적으로
- 모니터링 필수: 클러스터와 애플리케이션 상태를 지속적으로 관찰
- 보안 우선: 처음부터 보안을 고려한 설계와 운영
- 문서화: 클러스터 구성과 운영 절차를 반드시 문서화
Kubernetes를 마스터하고 클라우드 네이티브 시대의 핵심 기술을 정복해보세요! ☸️
'DevOps' 카테고리의 다른 글
| Terraform 완전 마스터 가이드: Infrastructure as Code로 클라우드 인프라 자동화 (2) | 2025.07.23 |
|---|---|
| Docker 완전 마스터 가이드: 초보자부터 프로덕션까지 컨테이너 기술 정복 (1) | 2025.07.23 |
| Git 완전 정복 가이드: 초보자부터 고급 사용자까지 버전 관리 마스터하기 (6) | 2025.07.23 |
| Linux OS 완전 가이드: 초보자부터 고급 사용자까지 (0) | 2025.07.23 |