Kubernetes: Triển khai ứng dụng đầu tiên

Hướng dẫn thực hành để triển khai ứng dụng trên Kubernetes. Từ cài đặt minikube đến Deployments, Services và ConfigMaps với các ví dụ cụ thể.

Hướng dẫn Kubernetes để triển khai ứng dụng đầu tiên

Kubernetes (K8s) đã trở thành tiêu chuẩn de facto cho việc điều phối container. Được thiết kế bởi Google và hiện được CNCF duy trì, Kubernetes tự động hóa việc triển khai, mở rộng và quản lý các ứng dụng được container hóa. Hướng dẫn này đi qua việc thiết lập một cluster cục bộ và triển khai ứng dụng đầu tiên.

Yêu cầu trước

Kiến thức cơ bản về Docker được khuyến nghị trước khi đi sâu vào Kubernetes. Container là các khối nền tảng mà Kubernetes điều phối. Đọc trước hướng dẫn Docker giúp việc hiểu các khái niệm được trình bày ở đây dễ dàng hơn rất nhiều.

Hiểu về kiến trúc Kubernetes

Kubernetes dựa trên kiến trúc master-worker. Control Plane đưa ra các quyết định toàn cục về cluster, trong khi các Node chạy các workload.

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 là điểm vào cho mọi lệnh. etcd lưu trữ trạng thái của cluster. Scheduler gán Pod cho các Node. Controller duy trì trạng thái mong muốn của hệ thống.

Thiết lập môi trường cục bộ

Có nhiều tùy chọn để thử nghiệm Kubernetes cục bộ: minikube, kind, k3d hoặc Docker Desktop. Minikube vẫn là giải pháp phổ biến nhất để học.

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 tạo một cluster Kubernetes một-node bên trong một máy ảo hoặc một container Docker. Tài nguyên được phân bổ (CPU, bộ nhớ) có thể được điều chỉnh theo nhu cầu.

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
Các lựa chọn thay thế Minikube

Kind (Kubernetes in Docker) khởi động nhanh hơn và phù hợp hơn cho việc kiểm thử CI/CD. K3d sử dụng k3s, một bản phân phối Kubernetes nhẹ. Docker Desktop tích hợp Kubernetes trực tiếp nhưng tiêu thụ nhiều tài nguyên hơn.

Pods: đơn vị cơ bản

Pod là đơn vị nhỏ nhất có thể triển khai trong Kubernetes. Một Pod đóng gói một hoặc nhiều container chia sẻ cùng một mạng và bộ lưu trữ.

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"

Manifest YAML này khai báo một Pod chứa một container nginx duy nhất. Các nhãn cho phép xác định và chọn các Pod. Tài nguyên xác định các đảm bảo tối thiểu (requests) và giới hạn tối đa (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 có bản chất là tạm thời. Trong trường hợp gặp sự cố hoặc bị xóa, Kubernetes không tự động tạo lại chúng. Deployment giải quyết hạn chế này.

Deployments: quản lý theo kiểu khai báo

Deployment xác định trạng thái mong muốn cho một tập hợp các Pod giống nhau. Kubernetes tự động duy trì trạng thái này bằng cách tạo, cập nhật hoặc xóa các Pod khi cần.

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 tạo một ReplicaSet duy trì 3 Pod giống nhau. Các probe kiểm tra trạng thái của các container và cho phép Kubernetes phản ứng tự động với các sự cố.

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

Xóa một Pod sẽ tự động kích hoạt việc tạo một Pod mới để duy trì số lượng bản sao mong muốn.

Sẵn sàng chinh phục phỏng vấn DevOps?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Services: phơi bày mạng

Các Pod có địa chỉ IP tạm thời. Services cung cấp một địa chỉ ổn định để truy cập một tập hợp các Pod, với cân bằng tải tích hợp.

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

Service ClusterIP này chỉ có thể truy cập được từ bên trong cluster. Các yêu cầu đến webapp-service:80 được phân phối giữa các Pod có nhãn app: webapp.

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

Để phơi bày ứng dụng ra ngoài cluster, cần loại NodePort hoặc 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

Với minikube, lệnh minikube service webapp-nodeport tự động mở trình duyệt tại đúng URL.

ConfigMaps: cấu hình bên ngoài

ConfigMap tách cấu hình khỏi mã nguồn. Các giá trị được tiêm dưới dạng biến môi trường hoặc gắn dưới dạng tệp.

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 lưu trữ dữ liệu không nhạy cảm. Đối với các bí mật (mật khẩu, token), Secrets của Kubernetes phù hợp hơn.

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

Cấu hình này tiêm các biến môi trường và gắn tệp nginx.conf vào bên trong container.

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
Cập nhật ConfigMap

Việc sửa đổi một ConfigMap không tự động khởi động lại các Pod. Để áp dụng thay đổi, cần khởi động lại thủ công: kubectl rollout restart deployment webapp-configured. Các công cụ như Reloader tự động hóa quy trình này.

Secrets: dữ liệu nhạy cảm

Secret lưu trữ thông tin nhạy cảm như mật khẩu, token hoặc khóa SSH. Mặc dù được mã hóa base64, chúng không được mã hóa mặc định khi ở trạng thái nghỉ.

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 được tiêm theo cùng cách như 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

Namespaces: cô lập logic

Namespace phân chia một cluster thành các môi trường ảo cô lập. Sự phân chia này cho phép quản lý nhiều nhóm hoặc môi trường trên cùng một cluster.

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

Mỗi tài nguyên có thể được tạo trong một namespace cụ thể.

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

Tài nguyên trong các namespace khác nhau được cô lập theo mặc định. Giao tiếp giữa các namespace được thực hiện thông qua DNS nội bộ: service-name.namespace.svc.cluster.local.

Ứng dụng hoàn chỉnh: lắp ráp các tài nguyên

Dưới đây là một ứng dụng hoàn chỉnh kết hợp tất cả các khái niệm đã trình bày.

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

Một tệp duy nhất này triển khai một ứng dụng hoàn chỉnh với cấu hình bên ngoài, các bí mật, tính sẵn sàng cao và phơi bày mạng.

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

Cập nhật và rollback

Kubernetes hỗ trợ các cập nhật tiến triển và rollback một cách dễ dàng.

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

Chiến lược cập nhật mặc định (RollingUpdate) thay thế dần các Pod cũ bằng các Pod mới, đảm bảo tính sẵn sàng liên tục.

Các lệnh kubectl thiết yếu

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

Kết luận

Kubernetes biến đổi việc quản lý các ứng dụng được container hóa bằng cách cung cấp một khuôn khổ khai báo, có khả năng phục hồi và mở rộng. Các khái niệm cơ bản được trình bày ở đây tạo nền tảng cho các triển khai sẵn sàng cho production.

Danh sách kiểm tra cho lần triển khai Kubernetes đầu tiên

  • ✅ Cluster cục bộ hoạt động (minikube, kind hoặc k3d)
  • ✅ kubectl đã cài đặt và cấu hình
  • ✅ Deployment với các bản sao và health probes
  • ✅ Service để phơi bày mạng
  • ✅ ConfigMap cho cấu hình bên ngoài
  • ✅ Secret cho dữ liệu nhạy cảm
  • ✅ Namespace để cô lập
  • ✅ Giới hạn tài nguyên đã được xác định (requests/limits)
  • ✅ Nắm vững chiến lược cập nhật và rollback

Bắt đầu luyện tập!

Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.

Thành thạo Kubernetes mở ra cánh cửa tới các kiến trúc cloud-native có khả năng mở rộng. Các bước tiếp theo bao gồm khám phá Ingress Controllers cho định tuyến HTTP, PersistentVolumes cho lưu trữ và Helm cho quản lý gói. Kubernetes trở thành một tài sản quan trọng trong các cuộc phỏng vấn DevOps và SRE.

Thẻ

#kubernetes
#k8s
#container orchestration
#devops
#deployment

Chia sẻ

Bài viết liên quan