Kubernetes μž…λ¬Έ

Kubernetes μž…λ¬Έ

1. Kubernetesλž€?

Kubernetes(K8s)λŠ” μ»¨ν…Œμ΄λ„ˆ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ ν”Œλž«νΌμž…λ‹ˆλ‹€. μ—¬λŸ¬ μ»¨ν…Œμ΄λ„ˆμ˜ 배포, ν™•μž₯, 관리λ₯Ό μžλ™ν™”ν•©λ‹ˆλ‹€.

Docker vs Kubernetes

Docker Kubernetes
μ»¨ν…Œμ΄λ„ˆ μ‹€ν–‰ μ»¨ν…Œμ΄λ„ˆ 관리/μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜
단일 호슀트 ν΄λŸ¬μŠ€ν„° (μ—¬λŸ¬ μ„œλ²„)
μˆ˜λ™ μŠ€μΌ€μΌλ§ μžλ™ μŠ€μΌ€μΌλ§
λ‹¨μˆœ 배포 둀링 μ—…λ°μ΄νŠΈ, λ‘€λ°±

μ™œ Kubernetesκ°€ ν•„μš”ν•œκ°€?

문제 상황:

μ»¨ν…Œμ΄λ„ˆκ°€ 100개일 λ•Œ...
- μ–΄λ–€ μ„œλ²„μ— 배포해야 ν•˜λ‚˜?
- μ»¨ν…Œμ΄λ„ˆκ°€ 죽으면 λˆ„κ°€ λ‹€μ‹œ μ‹œμž‘ν•˜λ‚˜?
- νŠΈλž˜ν”½μ΄ 늘면 μ–΄λ–»κ²Œ ν™•μž₯ν•˜λ‚˜?
- μƒˆ 버전 배포 쀑 λ‹€μš΄νƒ€μž„μ€?

Kubernetes ν•΄κ²°μ±…:

- μžλ™ μŠ€μΌ€μ€„λ§: 졜적의 λ…Έλ“œμ— 배치
- μžκ°€ 치유: μž₯μ•  μ‹œ μžλ™ 볡ꡬ
- μžλ™ μŠ€μΌ€μΌλ§: λΆ€ν•˜μ— 따라 ν™•μž₯/μΆ•μ†Œ
- 둀링 μ—…λ°μ΄νŠΈ: 무쀑단 배포

2. Kubernetes μ•„ν‚€ν…μ²˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Kubernetes Cluster                       β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚                   Control Plane                         β”‚ β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚  β”‚  β”‚ API     β”‚ β”‚ Schedulerβ”‚ β”‚ Controllerβ”‚ β”‚   etcd    β”‚ β”‚ β”‚
β”‚  β”‚  β”‚ Server  β”‚ β”‚          β”‚ β”‚  Manager  β”‚ β”‚           β”‚ β”‚ β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                            β”‚                                 β”‚
β”‚           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚           β”‚                β”‚                β”‚               β”‚
β”‚           β–Ό                β–Ό                β–Ό               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚   Node 1   β”‚   β”‚   Node 2   β”‚   β”‚   Node 3   β”‚          β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚          β”‚
β”‚  β”‚ β”‚ kubeletβ”‚ β”‚   β”‚ β”‚ kubeletβ”‚ β”‚   β”‚ β”‚ kubeletβ”‚ β”‚          β”‚
β”‚  β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚   β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚   β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚          β”‚
β”‚  β”‚ β”‚  Pod   β”‚ β”‚   β”‚ β”‚  Pod   β”‚ β”‚   β”‚ β”‚  Pod   β”‚ β”‚          β”‚
β”‚  β”‚ β”‚  Pod   β”‚ β”‚   β”‚ β”‚  Pod   β”‚ β”‚   β”‚ β”‚  Pod   β”‚ β”‚          β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

μ£Όμš” ꡬ성 μš”μ†Œ

ꡬ성 μš”μ†Œ μ—­ν• 
API Server λͺ¨λ“  μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” 쀑앙 κ²Œμ΄νŠΈμ›¨μ΄
Scheduler Podλ₯Ό μ–΄λŠ Node에 λ°°μΉ˜ν• μ§€ κ²°μ •
Controller Manager μ›ν•˜λŠ” μƒνƒœ μœ μ§€ (볡제, 배포 λ“±)
etcd ν΄λŸ¬μŠ€ν„° μƒνƒœ μ €μž₯μ†Œ
kubelet 각 Nodeμ—μ„œ μ»¨ν…Œμ΄λ„ˆ μ‹€ν–‰ 관리
kube-proxy λ„€νŠΈμ›Œν¬ ν”„λ‘μ‹œ, μ„œλΉ„μŠ€ λ‘œλ“œλ°ΈλŸ°μ‹±

3. 핡심 κ°œλ…

Pod

  • Kubernetes의 μ΅œμ†Œ 배포 λ‹¨μœ„
  • ν•˜λ‚˜ μ΄μƒμ˜ μ»¨ν…Œμ΄λ„ˆ 포함
  • 같은 Pod의 μ»¨ν…Œμ΄λ„ˆλŠ” λ„€νŠΈμ›Œν¬/μŠ€ν† λ¦¬μ§€ 곡유
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: nginx
      image: nginx:alpine
      ports:
        - containerPort: 80

Deployment

  • Pod의 선언적 배포 관리
  • 볡제본 수 관리 (ReplicaSet)
  • 둀링 μ—…λ°μ΄νŠΈ, λ‘€λ°± 지원
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 3                    # Pod 3개 μœ μ§€
  selector:
    matchLabels:
      app: my-app
  template:                      # Pod ν…œν”Œλ¦Ώ
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80

Service

  • Pod에 λŒ€ν•œ λ„€νŠΈμ›Œν¬ 접근점
  • λ‘œλ“œλ°ΈλŸ°μ‹±
  • Podκ°€ λ°”λ€Œμ–΄λ„ μΌκ΄€λœ μ ‘κ·Ό 제곡
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app                  # 이 라벨의 Pod둜 νŠΈλž˜ν”½ 전달
  ports:
    - port: 80                   # Service 포트
      targetPort: 80             # Pod 포트
  type: ClusterIP                # μ„œλΉ„μŠ€ νƒ€μž…

Service νƒ€μž…

νƒ€μž… μ„€λͺ…
ClusterIP ν΄λŸ¬μŠ€ν„° λ‚΄λΆ€μ—μ„œλ§Œ μ ‘κ·Ό (κΈ°λ³Έκ°’)
NodePort 각 Node의 포트둜 μ™ΈλΆ€ μ ‘κ·Ό
LoadBalancer ν΄λΌμš°λ“œ λ‘œλ“œλ°ΈλŸ°μ„œ μ—°κ²°

4. 둜컬 ν™˜κ²½ μ„€μ •

minikube μ„€μΉ˜

λ‘œμ»¬μ—μ„œ Kubernetesλ₯Ό μ‹€ν–‰ν•˜λŠ” λ„κ΅¬μž…λ‹ˆλ‹€.

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 μ‹œμž‘

# ν΄λŸ¬μŠ€ν„° μ‹œμž‘
minikube start

# μƒνƒœ 확인
minikube status

# λŒ€μ‹œλ³΄λ“œ μ—΄κΈ°
minikube dashboard

# ν΄λŸ¬μŠ€ν„° 쀑지
minikube stop

# ν΄λŸ¬μŠ€ν„° μ‚­μ œ
minikube delete

kubectl μ„€μΉ˜

Kubernetes ν΄λŸ¬μŠ€ν„°μ™€ ν†΅μ‹ ν•˜λŠ” CLI λ„κ΅¬μž…λ‹ˆλ‹€.

macOS:

brew install kubectl

Windows:

choco install kubernetes-cli

확인:

kubectl version --client

5. kubectl κΈ°λ³Έ λͺ…λ Ήμ–΄

λ¦¬μ†ŒμŠ€ 쑰회

# λͺ¨λ“  Pod 쑰회
kubectl get pods

# λͺ¨λ“  λ¦¬μ†ŒμŠ€ 쑰회
kubectl get all

# 상세 정보
kubectl get pods -o wide

# YAML ν˜•μ‹μœΌλ‘œ 좜λ ₯
kubectl get pod my-pod -o yaml

# λ„€μž„μŠ€νŽ˜μ΄μŠ€ μ§€μ •
kubectl get pods -n kube-system

λ¦¬μ†ŒμŠ€ 생성/μ‚­μ œ

# YAML 파일둜 생성
kubectl apply -f deployment.yaml

# μ‚­μ œ
kubectl delete -f deployment.yaml

# μ΄λ¦„μœΌλ‘œ μ‚­μ œ
kubectl delete pod my-pod
kubectl delete deployment my-deployment

상세 정보

# λ¦¬μ†ŒμŠ€ 상세 정보
kubectl describe pod my-pod
kubectl describe deployment my-deployment

# 둜그 확인
kubectl logs my-pod
kubectl logs -f my-pod              # μ‹€μ‹œκ°„

# μ»¨ν…Œμ΄λ„ˆ 접속
kubectl exec -it my-pod -- /bin/sh

μŠ€μΌ€μΌλ§

# 볡제본 수 λ³€κ²½
kubectl scale deployment my-deployment --replicas=5

6. μ‹€μŠ΅ 예제

예제 1: 첫 번째 Pod μ‹€ν–‰

# 1. Pod 직접 μ‹€ν–‰
kubectl run nginx-pod --image=nginx:alpine

# 2. 확인
kubectl get pods

# 3. 상세 정보
kubectl describe pod nginx-pod

# 4. 둜그 확인
kubectl logs nginx-pod

# 5. μ‚­μ œ
kubectl delete pod nginx-pod

예제 2: Deployment둜 μ•± 배포

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: hello
          image: nginxdemos/hello
          ports:
            - containerPort: 80
# 1. Deployment 생성
kubectl apply -f deployment.yaml

# 2. 확인
kubectl get deployments
kubectl get pods

# 3. Pod ν•˜λ‚˜ μ‚­μ œν•΄λ³΄κΈ° (μžλ™ 볡ꡬ 확인)
kubectl delete pod <pod-name>
kubectl get pods  # μƒˆ Podκ°€ 생성됨

# 4. μŠ€μΌ€μΌ μ—…
kubectl scale deployment hello-app --replicas=5
kubectl get pods

예제 3: Service둜 λ…ΈμΆœ

service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  selector:
    app: hello
  ports:
    - port: 80
      targetPort: 80
  type: NodePort
# 1. Service 생성
kubectl apply -f service.yaml

# 2. 확인
kubectl get services

# 3. minikubeμ—μ„œ μ ‘κ·Ό
minikube service hello-service

# λ˜λŠ” 포트 ν¬μ›Œλ”©
kubectl port-forward service/hello-service 8080:80
# http://localhost:8080 μ—μ„œ 확인

예제 4: 전체 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ (Node.js + MongoDB)

app-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: node-app
  template:
    metadata:
      labels:
        app: node-app
    spec:
      containers:
        - name: node
          image: node:18-alpine
          command: ["node", "-e", "require('http').createServer((req,res)=>{res.end('Hello K8s!')}).listen(3000)"]
          ports:
            - containerPort: 3000
          env:
            - name: MONGO_URL
              value: "mongodb://mongo-service:27017/mydb"
---
apiVersion: v1
kind: Service
metadata:
  name: node-service
spec:
  selector:
    app: node-app
  ports:
    - port: 80
      targetPort: 3000
  type: NodePort

mongo-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
        - name: mongo
          image: mongo:6
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-storage
              mountPath: /data/db
      volumes:
        - name: mongo-storage
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-service
spec:
  selector:
    app: mongo
  ports:
    - port: 27017
      targetPort: 27017
# 1. MongoDB 배포
kubectl apply -f mongo-deployment.yaml

# 2. Node.js μ•± 배포
kubectl apply -f app-deployment.yaml

# 3. 확인
kubectl get all

# 4. 접속
minikube service node-service

7. 둀링 μ—…λ°μ΄νŠΈ

μ—…λ°μ΄νŠΈ 적용

# 이미지 μ—…λ°μ΄νŠΈ
kubectl set image deployment/hello-app hello=nginxdemos/hello:latest

# λ˜λŠ” YAML μˆ˜μ • ν›„
kubectl apply -f deployment.yaml

μ—…λ°μ΄νŠΈ μƒνƒœ 확인

# 둀아웃 μƒνƒœ
kubectl rollout status deployment/hello-app

# νžˆμŠ€ν† λ¦¬
kubectl rollout history deployment/hello-app

λ‘€λ°±

# 이전 λ²„μ „μœΌλ‘œ λ‘€λ°±
kubectl rollout undo deployment/hello-app

# νŠΉμ • λ²„μ „μœΌλ‘œ λ‘€λ°±
kubectl rollout undo deployment/hello-app --to-revision=2

8. ConfigMapκ³Ό Secret

ConfigMap - μ„€μ • 데이터

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "db-service"
  LOG_LEVEL: "info"

Deploymentμ—μ„œ μ‚¬μš©:

spec:
  containers:
    - name: app
      envFrom:
        - configMapRef:
            name: app-config

Secret - λ―Όκ°ν•œ 데이터

# Secret 생성
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password=secret123
# YAML둜 생성 (base64 인코딩 ν•„μš”)
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=      # echo -n 'admin' | base64
  password: c2VjcmV0MTIz  # echo -n 'secret123' | base64

Deploymentμ—μ„œ μ‚¬μš©:

spec:
  containers:
    - name: app
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password

9. λ„€μž„μŠ€νŽ˜μ΄μŠ€

λ¦¬μ†ŒμŠ€λ₯Ό λ…Όλ¦¬μ μœΌλ‘œ λΆ„λ¦¬ν•©λ‹ˆλ‹€.

# λ„€μž„μŠ€νŽ˜μ΄μŠ€ 생성
kubectl create namespace dev
kubectl create namespace prod

# νŠΉμ • λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— 배포
kubectl apply -f deployment.yaml -n dev

# κΈ°λ³Έ λ„€μž„μŠ€νŽ˜μ΄μŠ€ λ³€κ²½
kubectl config set-context --current --namespace=dev

λͺ…λ Ήμ–΄ μš”μ•½

λͺ…λ Ήμ–΄ μ„€λͺ…
kubectl get pods Pod λͺ©λ‘
kubectl get all λͺ¨λ“  λ¦¬μ†ŒμŠ€
kubectl apply -f file.yaml λ¦¬μ†ŒμŠ€ 생성/μ—…λ°μ΄νŠΈ
kubectl delete -f file.yaml λ¦¬μ†ŒμŠ€ μ‚­μ œ
kubectl describe pod name 상세 정보
kubectl logs pod-name 둜그 확인
kubectl exec -it pod -- sh μ»¨ν…Œμ΄λ„ˆ 접속
kubectl scale deployment name --replicas=N μŠ€μΌ€μΌλ§
kubectl rollout status 배포 μƒνƒœ
kubectl rollout undo λ‘€λ°±

λ‹€μŒ ν•™μŠ΅ μΆ”μ²œ

  1. Ingress: HTTP λΌμš°νŒ…, SSL 처리
  2. Persistent Volume: 영ꡬ μ €μž₯μ†Œ
  3. Helm: νŒ¨ν‚€μ§€ κ΄€λ¦¬μž
  4. λͺ¨λ‹ˆν„°λ§: Prometheus, Grafana
  5. μ„œλΉ„μŠ€ λ©”μ‹œ: Istio, Linkerd

μΆ”κ°€ ν•™μŠ΅ 자료

to navigate between lessons