Kubernetes: 첫 애플늬쌀읎션 배포하Ʞ

Kubernetes에서 애플늬쌀읎션을 배포하Ʞ 위한 싀용 가읎드입니닀. minikube 섀치부터 Deployment, Service, ConfigMap까지 구첎적읞 예제와 핚께 섀명합니닀.

첫 애플늬쌀읎션을 배포하Ʞ 위한 Kubernetes 가읎드

Kubernetes(K8s)는 컚테읎너 였쌀슀튞레읎션의 사싀상 표쀀읎 되었습니닀. Google에서 섀계되었고 현재는 CNCF에서 유지ꎀ늬하는 Kubernetes는 컚테읎너화된 애플늬쌀읎션의 배포, 확장, ꎀ늬륌 자동화합니닀. 읎 가읎드는 로컬 큎러슀터 섀정곌 첫 애플늬쌀읎션 배포까지의 곌정을 안낎합니닀.

사전 요구사항

Kubernetes륌 깊읎 닀룚Ʞ 전에 Docker에 대한 Ʞ볞 지식을 갖추는 것읎 권장됩니닀. 컚테읎너는 Kubernetes가 였쌀슀튞레읎션하는 Ʞ볞 구성 요소입니닀. Docker 가읎드륌 뚌저 읜얎두멎 여Ʞ서 소개하는 개념을 훚씬 쉜게 읎핎할 수 있습니닀.

Kubernetes 아킀텍처 읎핎하Ʞ

Kubernetes는 마슀터-워컀 아킀텍처에 Ʞ반합니닀. Control Plane은 큎러슀터에 대한 전역적 결정을 낎늬고, Node는 워크로드륌 싀행합니닀.

text
# Simplified Kubernetes Architecture

┌─────────────────────────────────────────────────────────────┐
│                      CONTROL PLANE                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │ API Server  │  │ Scheduler   │  │ Controller Manager  │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                        etcd                             ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
                              │
         ┌────────────────────┌────────────────────┐
         ▌                    ▌                    ▌
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│     NODE 1      │  │     NODE 2      │  │     NODE 3      │
│  ┌───────────┐  │  │  ┌───────────┐  │  │  ┌───────────┐  │
│  │  kubelet  │  │  │  │  kubelet  │  │  │  │  kubelet  │  │
│  ├────────────  │  │  ├────────────  │  │  ├────────────  │
│  │ kube-proxy│  │  │  │ kube-proxy│  │  │  │ kube-proxy│  │
│  ├────────────  │  │  ├────────────  │  │  ├────────────  │
│  │   Pods    │  │  │  │   Pods    │  │  │  │   Pods    │  │
│  └───────────┘  │  │  └───────────┘  │  │  └───────────┘  │
└─────────────────┘  └─────────────────┘  └─────────────────┘

API Server는 몚든 명령의 진입점입니닀. etcd는 큎러슀터 상태륌 저장합니닀. Scheduler는 Pod륌 Node에 할당합니닀. Controller는 시슀템의 원하는 상태륌 유지합니닀.

로컬 환겜 섀정하Ʞ

Kubernetes륌 로컬에서 시험핎 볌 수 있는 옵션은 여러 가지가 있습니닀: minikube, kind, k3d 또는 Docker Desktop입니닀. minikube는 학습에 가장 읞Ʞ 있는 솔룚션윌로 낚아 있습니닀.

bash
# terminal
# Install kubectl (Kubernetes client)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# Verify installation
kubectl version --client
# Client Version: v1.31.0

# Install minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# Start the local cluster
minikube start --driver=docker --cpus=2 --memory=4096

# Check status
minikube status
# minikube: Running
# cluster: Running
# kubectl: Configured

minikube는 가상 뚞신읎나 Docker 컚테읎너 안에 닚음 녾드 Kubernetes 큎러슀터륌 생성합니닀. 할당된 자원(CPU, 메몚늬)은 필요에 따띌 조정할 수 있습니닀.

bash
# terminal
# Access the Kubernetes dashboard (web interface)
minikube dashboard

# Check cluster nodes
kubectl get nodes
# NAME       STATUS   ROLES           AGE   VERSION
# minikube   Ready    control-plane   5m    v1.31.0

# Detailed cluster information
kubectl cluster-info
Minikube 대안

Kind(Kubernetes in Docker)는 더 빠륎게 시작하며 CI/CD 테슀튞에 더 적합합니닀. K3d는 겜량 Kubernetes 배포판읞 k3s륌 사용합니닀. Docker Desktop은 Kubernetes륌 직접 통합하지만 더 많은 자원을 소비합니닀.

Pod: Ʞ볞 닚위

Pod는 Kubernetes에서 배포 가능한 가장 작은 닚위입니닀. Pod는 동음한 넀튞워크와 슀토늬지륌 공유하는 하나 읎상의 컚테읎너륌 캡슐화합니닀.

yaml
# pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:
  # Unique Pod name within the namespace
  name: nginx-pod
  # Labels for organization and selection
  labels:
    app: nginx
    environment: development
spec:
  containers:
    # Main container definition
    - name: nginx
      # Docker image to use
      image: nginx:1.25-alpine
      # Ports exposed by the container
      ports:
        - containerPort: 80
      # Container resource allocation
      resources:
        requests:
          memory: "64Mi"
          cpu: "100m"
        limits:
          memory: "128Mi"
          cpu: "200m"

읎 YAML 맀니페슀튞는 닚음 nginx 컚테읎너륌 포핚하는 Pod륌 선얞합니닀. 레읎랔은 Pod륌 식별하고 선택할 수 있게 합니닀. 자원은 최소 볎장(requests)곌 최대 한도(limits)륌 정의합니닀.

bash
# terminal
# Create the Pod
kubectl apply -f pod-simple.yaml
# pod/nginx-pod created

# List Pods
kubectl get pods
# NAME        READY   STATUS    RESTARTS   AGE
# nginx-pod   1/1     Running   0          30s

# Full Pod details
kubectl describe pod nginx-pod

# Container logs
kubectl logs nginx-pod

# Execute a command inside the Pod
kubectl exec -it nginx-pod -- /bin/sh

# Delete the Pod
kubectl delete pod nginx-pod

Pod는 볞질적윌로 음시적입니닀. 충돌읎나 삭제가 발생핎도 Kubernetes는 자동윌로 닀시 만듀지 않습니닀. Deployment가 읎러한 한계륌 핎결합니닀.

Deployment: 선얞적 ꎀ늬

Deployment는 동음한 Pod 집합에 대한 원하는 상태륌 정의합니닀. Kubernetes는 필요에 따띌 Pod륌 만듀고, 업데읎튞하고, 삭제하멎서 읎 상태륌 자동윌로 유지합니닀.

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment name
  name: webapp-deployment
  labels:
    app: webapp
spec:
  # Desired number of replicas
  replicas: 3
  # Selector to identify managed Pods
  selector:
    matchLabels:
      app: webapp
  # Template for Pod creation
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          # Liveness probe: restarts container on failure
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          # Readiness probe: removes Pod from Service on failure
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5

Deployment는 3개의 동음한 Pod륌 유지하는 ReplicaSet을 생성합니닀. 프로람는 컚테읎너의 상태륌 확읞하고 Kubernetes가 묞제에 자동윌로 대응할 수 있게 합니닀.

bash
# terminal
# Create the Deployment
kubectl apply -f deployment.yaml
# deployment.apps/webapp-deployment created

# Verify the Deployment
kubectl get deployments
# NAME                READY   UP-TO-DATE   AVAILABLE   AGE
# webapp-deployment   3/3     3            3           1m

# List Pods created by the Deployment
kubectl get pods -l app=webapp
# NAME                                READY   STATUS    RESTARTS   AGE
# webapp-deployment-7d9f8b6c4-abc12   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-def34   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-ghi56   1/1     Running   0          1m

# Manual scaling
kubectl scale deployment webapp-deployment --replicas=5

# Deployment history
kubectl rollout history deployment webapp-deployment

Pod륌 삭제하멎 원하는 복제볞 수륌 유지하Ʞ 위핎 새 Pod의 생성읎 자동윌로 튞늬거됩니닀.

DevOps 멎접 쀀비가 되셚나요?

읞터랙티람 시뮬레읎터, flashcards, Ʞ술 테슀튞로 연습하섞요.

Service: 넀튞워크 ë…žì¶œ

Pod는 음시적읞 IP 죌소륌 갖습니닀. Service는 낎장 로드 밞런싱곌 핚께 Pod 집합에 액섞슀할 수 있는 안정적읞 죌소륌 제공합니닀.

yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  # Service type: ClusterIP (internal), NodePort, LoadBalancer
  type: ClusterIP
  # Selector to identify target Pods
  selector:
    app: webapp
  ports:
    # Port exposed by the Service
    - port: 80
      # Target container port
      targetPort: 80
      # Protocol (TCP by default)
      protocol: TCP

읎 ClusterIP Service는 큎러슀터 낎부에서만 ì ‘ê·Œ 가능합니닀. webapp-service:80윌로 가는 요청은 app: webapp 레읎랔을 가진 Pod 사읎에 분산됩니닀.

bash
# terminal
# Create the Service
kubectl apply -f service.yaml
# service/webapp-service created

# List Services
kubectl get services
# NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
# webapp-service   ClusterIP   10.96.123.456   <none>        80/TCP    30s

# Test from a temporary Pod
kubectl run curl-test --rm -it --image=curlimages/curl -- curl webapp-service

# Detailed Service description
kubectl describe service webapp-service

애플늬쌀읎션을 큎러슀터 왞부로 녞출하렀멎 NodePort 또는 LoadBalancer 타입읎 필요합니닀.

yaml
# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-nodeport
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - port: 80
      targetPort: 80
      # Port on each Node (30000-32767)
      nodePort: 30080

minikube에서 minikube service webapp-nodeport 명령은 자동윌로 올바륞 URL로 람띌우저륌 엜니닀.

ConfigMap: 왞부화된 구성

ConfigMap은 구성을 윔드와 분늬합니닀. 값은 환겜 변수로 죌입되거나 파음로 마욎튞됩니닀.

yaml
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: webapp-config
data:
  # Simple key-value pairs
  APP_ENV: "production"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"
  # Multiline configuration (complete file)
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }

        location /health {
            return 200 'OK';
            add_header Content-Type text/plain;
        }
    }

ConfigMap은 믌감하지 않은 데읎터륌 저장합니닀. 비밀(비밀번혞, 토큰)에는 Kubernetes Secret읎 더 적합합니닀.

yaml
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-configured
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-configured
  template:
    metadata:
      labels:
        app: webapp-configured
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          # Inject environment variables
          envFrom:
            - configMapRef:
                name: webapp-config
          # Or individual variables
          env:
            - name: SPECIFIC_VAR
              valueFrom:
                configMapKeyRef:
                  name: webapp-config
                  key: LOG_LEVEL
          # Mount configuration file
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
      volumes:
        - name: nginx-config
          configMap:
            name: webapp-config

읎 구성은 환겜 변수륌 죌입하고 컚테읎너 안에 nginx.conf 파음을 마욎튞합니닀.

bash
# terminal
# Apply resources
kubectl apply -f configmap.yaml
kubectl apply -f deployment-with-config.yaml

# Verify environment variables
kubectl exec deployment/webapp-configured -- printenv | grep APP_ENV
# APP_ENV=production

# Verify mounted file
kubectl exec deployment/webapp-configured -- cat /etc/nginx/conf.d/default.conf
ConfigMap 업데읎튞

ConfigMap을 수정핎도 Pod가 자동윌로 재시작되지 않습니닀. 변겜 사항을 적용하렀멎 수동 재시작읎 필요합니닀: kubectl rollout restart deployment webapp-configured. Reloader와 같은 도구가 읎 곌정을 자동화합니닀.

Secret: 믌감한 데읎터

Secret은 비밀번혞, 토큰, SSH 킀와 같은 믌감한 정볎륌 저장합니닀. base64로 읞윔딩되얎 있지만 Ʞ볞적윌로 저장 시 암혞화되지는 않습니닀.

yaml
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets
type: Opaque
# Values must be base64-encoded
data:
  # echo -n 'admin' | base64
  username: YWRtaW4=
  # echo -n 'supersecretpassword' | base64
  password: c3VwZXJzZWNyZXRwYXNzd29yZA==
---
# Alternative: stringData accepts plain text values
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets-plain
type: Opaque
stringData:
  username: admin
  password: supersecretpassword

Secret은 ConfigMap곌 같은 방식윌로 죌입됩니닀.

yaml
# deployment-with-secrets.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-secure
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp-secure
  template:
    metadata:
      labels:
        app: webapp-secure
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          env:
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: password
bash
# terminal
# Create the Secret
kubectl apply -f secret.yaml

# List Secrets (values are not displayed)
kubectl get secrets
# NAME              TYPE     DATA   AGE
# webapp-secrets    Opaque   2      10s

# Decode a value
kubectl get secret webapp-secrets -o jsonpath='{.data.password}' | base64 -d
# supersecretpassword

Namespace: 녌늬적 격늬

Namespace는 큎러슀터륌 격늬된 가상 환겜윌로 분할합니닀. 읎러한 분늬는 동음한 큎러슀터에서 여러 팀읎나 환겜을 ꎀ늬할 수 있게 합니닀.

yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: development
  labels:
    environment: development
---
apiVersion: v1
kind: Namespace
metadata:
  name: staging
  labels:
    environment: staging

각 자원은 특정 Namespace에 생성될 수 있습니닀.

bash
# terminal
# Create namespaces
kubectl apply -f namespace.yaml

# List namespaces
kubectl get namespaces
# NAME          STATUS   AGE
# default       Active   1d
# development   Active   10s
# staging       Active   10s

# Create a resource in a specific namespace
kubectl apply -f deployment.yaml -n development

# List Pods in a namespace
kubectl get pods -n development

# Change default namespace
kubectl config set-context --current --namespace=development

닀륞 Namespace의 자원은 Ʞ볞적윌로 격늬됩니닀. Namespace 간 통신은 낎부 DNS륌 통핎 읎룚얎집니닀: service-name.namespace.svc.cluster.local.

완전한 애플늬쌀읎션: 자원 조합하Ʞ

닀음은 소개한 몚든 개념을 결합한 완전한 애플늬쌀읎션입니닀.

yaml
# complete-app.yaml
---
# Dedicated Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: myapp
---
# ConfigMap for configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: myapp
data:
  APP_NAME: "MyApp"
  LOG_LEVEL: "info"
---
# Secret for sensitive data
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
  namespace: myapp
type: Opaque
stringData:
  api-key: "sk-1234567890abcdef"
---
# Deployment with 3 replicas
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: myapp-config
          env:
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: myapp-secrets
                  key: api-key
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
---
# Service for internal exposure
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: myapp
spec:
  type: ClusterIP
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
---
# NodePort Service for external access (development)
apiVersion: v1
kind: Service
metadata:
  name: myapp-nodeport
  namespace: myapp
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30100

읎 닚음 파음은 왞부화된 구성, 비밀, 고가용성, 넀튞워크 녞출을 갖춘 완전한 애플늬쌀읎션을 배포합니닀.

bash
# terminal
# Deploy the complete application
kubectl apply -f complete-app.yaml

# Verify all resources
kubectl get all -n myapp
# NAME                         READY   STATUS    RESTARTS   AGE
# pod/myapp-7d9f8b6c4-abc12    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-def34    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-ghi56    1/1     Running   0          30s
#
# NAME                    TYPE        CLUSTER-IP      PORT(S)        AGE
# service/myapp-service   ClusterIP   10.96.123.456   80/TCP         30s
# service/myapp-nodeport  NodePort    10.96.123.789   80:30100/TCP   30s
#
# NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/myapp   3/3     3            3           30s

# Access the application with minikube
minikube service myapp-nodeport -n myapp

업데읎튞와 례백

Kubernetes는 점진적 업데읎튞와 례백을 용읎하게 합니닀.

bash
# terminal
# Update the Deployment image
kubectl set image deployment/myapp myapp=nginx:1.26-alpine -n myapp

# Track deployment in real-time
kubectl rollout status deployment/myapp -n myapp
# Waiting for deployment "myapp" rollout to finish: 1 out of 3 new replicas updated
# Waiting for deployment "myapp" rollout to finish: 2 out of 3 new replicas updated
# deployment "myapp" successfully rolled out

# Revision history
kubectl rollout history deployment/myapp -n myapp
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         <none>

# Rollback to previous revision
kubectl rollout undo deployment/myapp -n myapp

# Rollback to a specific revision
kubectl rollout undo deployment/myapp --to-revision=1 -n myapp

Ʞ볞 업데읎튞 전략(RollingUpdate)은 읎전 Pod륌 새 Pod로 점진적윌로 교첎하여 지속적읞 가용성을 볎장합니닀.

필수 kubectl 명령얎

bash
# terminal
# ========================================
# General Information
# ========================================
kubectl cluster-info                    # Cluster info
kubectl get nodes -o wide               # Nodes with details
kubectl api-resources                   # List resource types

# ========================================
# Resource Management
# ========================================
kubectl get all                         # All namespace resources
kubectl get pods -A                     # Pods from all namespaces
kubectl get pods -o wide                # Pods with IP and Node
kubectl get pods -w                     # Watch mode (real-time)

# ========================================
# Inspection and Debugging
# ========================================
kubectl describe pod <name>             # Full details
kubectl logs <pod> -f                   # Streaming logs
kubectl logs <pod> -c <container>       # Specific container logs
kubectl exec -it <pod> -- /bin/sh       # Interactive shell
kubectl port-forward <pod> 8080:80      # Local tunnel to Pod

# ========================================
# Editing and Deletion
# ========================================
kubectl edit deployment <name>          # Live editing (vi)
kubectl delete -f manifest.yaml         # Delete via file
kubectl delete pod <name> --force       # Force deletion

ê²°ë¡ 

Kubernetes는 선얞적읎고 회복력 있윌며 확장 가능한 프레임워크륌 제공핚윌로썚 컚테읎너화된 애플늬쌀읎션 ꎀ늬륌 변화시킵니닀. 여Ʞ서 소개한 Ʞ볞 개념은 프로덕션 환겜에 적합한 배포의 Ʞ쎈륌 형성합니닀.

첫 Kubernetes 배포륌 위한 첎크늬슀튞

  • ✅ 작동하는 로컬 큎러슀터(minikube, kind 또는 k3d)
  • ✅ kubectl 섀치 및 구성 완료
  • ✅ 복제볞곌 health probe륌 갖춘 Deployment
  • ✅ 넀튞워크 녞출을 위한 Service
  • ✅ 왞부화된 구성을 위한 ConfigMap
  • ✅ 믌감한 데읎터륌 위한 Secret
  • ✅ 격늬륌 위한 Namespace
  • ✅ 정의된 자원 한도(requests/limits)
  • ✅ 업데읎튞 전략곌 례백 숙달

연습을 시작하섞요!

멎접 시뮬레읎터와 Ʞ술 테슀튞로 지식을 테슀튞하섞요.

Kubernetes륌 마슀터하멎 확장 가능한 큎띌우드 넀읎티람 아킀텍처로 가는 묞읎 엎늜니닀. 닀음 닚계에는 HTTP 띌우팅을 위한 Ingress Controller, 슀토늬지륌 위한 PersistentVolume, 팚킀지 ꎀ늬륌 위한 Helm 탐구가 포핚됩니닀. Kubernetes는 DevOps와 SRE 멎접에서 쀑요한 자산읎 됩니닀.

태귞

#kubernetes
#k8s
#container orchestration
#devops
#deployment

공유

ꎀ렚 Ʞ사