Module 15 Container Orchestration 5 labs

Kubernetes Core

Nắm vững nền tảng Kubernetes: Pod, Deployment, Service, ConfigMap, Secret, Ingress, Namespace, RBAC và kỹ năng troubleshooting thực chiến bằng kubectl.

Công cụ thực hành kubectl, kind / minikube, Helm, VS Code
Nền tảng Linux (WSL2) / macOS / Windows — Kubernetes local (kind/minikube)
Thời điểm phát hành 23/05/2026
Ngày biên soạn 23/05/2026
Người biên soạn Trần Văn Hòa — Microsoft Certified Trainer (MCT)

Mục tiêu học tập

1. Lý thuyết cốt lõi

1.1. Kiến trúc Kubernetes

Kubernetes (K8s) là hệ thống điều phối container mã nguồn mở, ra đời từ Google Borg. Cluster gồm hai lớp: Control Plane (điều phối) và Worker Nodes (chạy workload).

Control Plane components

  • kube-apiserver — cổng duy nhất vào cluster, xác thực/ủy quyền mọi request.
  • etcd — key-value store phân tán, lưu toàn bộ trạng thái cluster.
  • kube-scheduler — quyết định Pod chạy trên Node nào (dựa vào resources, taints, affinity).
  • kube-controller-manager — chạy các controller loop: ReplicaSet, Deployment, Node, Job…
  • cloud-controller-manager — tích hợp với cloud provider (LoadBalancer, PV provisioner).

Worker Node components

  • kubelet — agent chạy trên mỗi Node, nhận PodSpec từ API server, giao tiếp với container runtime.
  • kube-proxy — duy trì iptables/IPVS rules để route traffic tới Service.
  • Container Runtime — containerd / CRI-O chạy container theo OCI spec.

1.2. Các đối tượng cốt lõi

ObjectVai tròGhi chú
PodĐơn vị nhỏ nhất; 1+ container chia sẻ network/IPCEphemeral — không dùng Pod trực tiếp trong production
DeploymentQuản lý ReplicaSet, rolling update, rollbackDùng cho stateless app
ServiceStable IP + DNS cho nhóm Pod (selector)ClusterIP / NodePort / LoadBalancer / ExternalName
IngressHTTP/HTTPS routing từ ngoài vào ServiceCần Ingress Controller (nginx, traefik…)
ConfigMapLưu cấu hình non-sensitive (key-value / file)Mount Volume hoặc envFrom
SecretLưu dữ liệu nhạy cảm (base64 encoded)Mặc định không encrypt at-rest; cần EncryptionConfig
NamespacePhân vùng logic trong clusterResource quota, network policy per-namespace
ServiceAccountIdentity cho Pod khi gọi API serverKết hợp Role/RoleBinding (RBAC)

1.3. Networking cơ bản

Kubernetes flat network model: mọi Pod có IP riêng, có thể reach nhau trực tiếp. CNI plugin (Flannel, Calico, Cilium) thực thi model này. kube-dns / CoreDNS cung cấp DNS nội bộ: <service>.<namespace>.svc.cluster.local. Traffic vào cluster đi qua Ingress Controller (Layer 7) hoặc LoadBalancer Service (Layer 4).

1.4. RBAC — phân quyền theo nguyên tắc least-privilege

RBAC dùng 4 object: Role (namespace-scoped, danh sách verbs trên resources), ClusterRole (cluster-scoped), RoleBinding (gán Role cho Subject trong namespace), ClusterRoleBinding. Subject là User, Group hoặc ServiceAccount.

# Kiểm tra quyền của ServiceAccount hiện tại
kubectl auth can-i list pods --namespace=dev
kubectl auth can-i create deployments --namespace=dev --as=system:serviceaccount:dev:ci-bot

1.5. Vòng đời Pod và trạng thái lỗi

Pod đi qua: Pending → Running → Succeeded/Failed. Container status quan trọng hơn Pod status khi debug:

2. Thực hành (Labs)

LAB-071

Deploy app lên Kubernetes

kubectl · kind/minikube

🎯 Mục tiêu: Tạo cluster local, deploy một ứng dụng stateless với Deployment và kiểm tra Pod đang chạy.

🧰 Công cụ / nền tảng: kubectl, kind (hoặc minikube), VS Code.

📦 Chuẩn bị: Cài kind + kubectl; Docker Desktop hoặc Docker Engine đang chạy.

▶️ Các bước:

# 1. Tạo cluster local
kind create cluster --name k8s-lab
kubectl cluster-info --context kind-k8s-lab

# 2. Tạo file deployment.yaml
cat > nginx-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: default
  labels:
    app: nginx-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx
        image: nginx:1.27-alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"
EOF

# 3. Apply và theo dõi
kubectl apply -f nginx-deployment.yaml
kubectl rollout status deployment/nginx-demo

# 4. Kiểm tra Pod
kubectl get pods -o wide
kubectl describe pod <pod-name>

# 5. Xem log
kubectl logs -l app=nginx-demo --tail=20

✅ Kết quả mong đợi: kubectl get pods cho thấy 3 Pod trạng thái Running; kubectl rollout status báo "successfully rolled out".

🧹 Cleanup: kubectl delete -f nginx-deployment.yaml (giữ cluster cho các lab tiếp theo).

LAB-072

Expose Service và Ingress

kubectl · nginx-ingress-controller

🎯 Mục tiêu: Tạo ClusterIP Service, NodePort Service và Ingress rule để route HTTP traffic từ ngoài vào app.

🧰 Công cụ / nền tảng: kubectl, kind (với port mapping), nginx Ingress Controller.

📦 Chuẩn bị: Cluster từ LAB-071 đang chạy; cài nginx Ingress Controller.

▶️ Các bước:

# 1. Tạo lại cluster với port mapping (nếu cần)
kind create cluster --name k8s-lab --config - <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 80
    hostPort: 8080
    protocol: TCP
  - containerPort: 443
    hostPort: 8443
    protocol: TCP
EOF

# 2. Cài nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

# 3. Deploy lại app + tạo Service
kubectl apply -f nginx-deployment.yaml

cat > nginx-service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx-demo
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP
EOF
kubectl apply -f nginx-service.yaml

# 4. Tạo Ingress
cat > nginx-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: demo.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80
EOF
kubectl apply -f nginx-ingress.yaml

# 5. Test
echo "127.0.0.1 demo.local" | sudo tee -a /etc/hosts
curl -H "Host: demo.local" http://localhost:8080

# 6. Kiểm tra Ingress
kubectl get ingress
kubectl describe ingress nginx-ingress

✅ Kết quả mong đợi: curl trả về trang HTML của nginx (HTTP 200); kubectl get ingress hiển thị ADDRESS là localhost.

🧹 Cleanup: kubectl delete -f nginx-ingress.yaml -f nginx-service.yaml. Xoá dòng hosts đã thêm.

LAB-073

ConfigMap và Secret cho ứng dụng

kubectl · YAML

🎯 Mục tiêu: Tạo ConfigMap chứa cấu hình app, Secret chứa thông tin đăng nhập DB, mount vào Pod qua envFrom và Volume.

🧰 Công cụ / nền tảng: kubectl, VS Code.

📦 Chuẩn bị: Cluster đang chạy; namespace dev được tạo.

▶️ Các bước:

# 1. Tạo namespace
kubectl create namespace dev

# 2. Tạo ConfigMap từ literal
kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=LOG_LEVEL=info \
  --namespace=dev
kubectl describe configmap app-config -n dev

# 3. Tạo ConfigMap từ file nginx.conf
cat > nginx.conf <<'EOF'
server {
    listen 80;
    server_name _;
    location /healthz { return 200 "OK"; }
}
EOF
kubectl create configmap nginx-conf --from-file=nginx.conf -n dev

# 4. Tạo Secret (encode base64 tự động qua kubectl)
kubectl create secret generic db-secret \
  --from-literal=DB_USER=appuser \
  --from-literal=DB_PASSWORD='S3cretP@ss!' \
  --namespace=dev
# Xem secret (encoded)
kubectl get secret db-secret -n dev -o yaml

# 5. Deploy app sử dụng ConfigMap + Secret
cat > app-with-config.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: config-demo
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: config-demo
  template:
    metadata:
      labels:
        app: config-demo
    spec:
      containers:
      - name: app
        image: busybox:1.36
        command: ["sh", "-c", "env | grep -E 'APP_ENV|LOG_LEVEL|DB_' && sleep 3600"]
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: db-secret
        volumeMounts:
        - name: nginx-config-vol
          mountPath: /etc/nginx/conf.d
          readOnly: true
      volumes:
      - name: nginx-config-vol
        configMap:
          name: nginx-conf
EOF
kubectl apply -f app-with-config.yaml

# 6. Xác nhận env vars được inject
kubectl exec -n dev deploy/config-demo -- env | grep -E 'APP_ENV|LOG_LEVEL|DB_'
kubectl exec -n dev deploy/config-demo -- ls /etc/nginx/conf.d/

✅ Kết quả mong đợi: env | grep hiển thị đủ 4 biến (APP_ENV=production, LOG_LEVEL=info, DB_USER, DB_PASSWORD); ls /etc/nginx/conf.d/ thấy file nginx.conf.

🧹 Cleanup: kubectl delete namespace dev (xoá toàn bộ resource trong namespace).

LAB-074

RBAC namespace cho team

kubectl · RBAC

🎯 Mục tiêu: Tạo ServiceAccount cho CI bot, gán Role read-only trong namespace staging, kiểm tra quyền với kubectl auth can-i.

🧰 Công cụ / nền tảng: kubectl, openssl (tạo kubeconfig test).

📦 Chuẩn bị: Cluster đang chạy.

▶️ Các bước:

# 1. Tạo namespace và ServiceAccount
kubectl create namespace staging
kubectl create serviceaccount ci-bot -n staging

# 2. Tạo Role: chỉ cho phép get/list/watch pods và deployments
cat > ci-role.yaml <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ci-readonly
  namespace: staging
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "replicasets", "services"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get"]
EOF
kubectl apply -f ci-role.yaml

# 3. Tạo RoleBinding
cat > ci-rolebinding.yaml <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-bot-binding
  namespace: staging
subjects:
- kind: ServiceAccount
  name: ci-bot
  namespace: staging
roleRef:
  kind: Role
  name: ci-readonly
  apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f ci-rolebinding.yaml

# 4. Kiểm tra quyền
kubectl auth can-i list pods \
  --namespace=staging \
  --as=system:serviceaccount:staging:ci-bot
# Kết quả mong đợi: yes

kubectl auth can-i delete pods \
  --namespace=staging \
  --as=system:serviceaccount:staging:ci-bot
# Kết quả mong đợi: no

kubectl auth can-i list pods \
  --namespace=default \
  --as=system:serviceaccount:staging:ci-bot
# Kết quả mong đợi: no (chỉ có quyền trong namespace staging)

# 5. Xem toàn bộ RBAC trong namespace
kubectl get roles,rolebindings -n staging

✅ Kết quả mong đợi: can-i list pods → yes; can-i delete pods → no; can-i list pods -n default → no. RBAC hoạt động đúng principle of least privilege.

🧹 Cleanup: kubectl delete namespace staging.

LAB-075

Troubleshoot CrashLoopBackOff

kubectl · debug

🎯 Mục tiêu: Tái hiện và chẩn đoán 3 lỗi thường gặp (CrashLoopBackOff, ImagePullBackOff, OOMKilled) bằng quy trình debug có hệ thống.

🧰 Công cụ / nền tảng: kubectl, kubectl debug (ephemeral container).

📦 Chuẩn bị: Cluster đang chạy.

▶️ Các bước:

## --- Kịch bản 1: CrashLoopBackOff ---
cat > crash-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: crash-demo
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh", "-c", "echo starting; exit 1"]
EOF
kubectl apply -f crash-pod.yaml

# Quan sát trạng thái
kubectl get pod crash-demo -w     # theo dõi real-time
kubectl describe pod crash-demo   # xem Events và Last State
kubectl logs crash-demo           # log hiện tại
kubectl logs crash-demo --previous  # log của lần chạy trước

# Fix: sửa command thành "sleep 3600"
kubectl patch pod crash-demo --patch '{"spec":{"containers":[{"name":"app","command":["sleep","3600"]}]}}' 2>/dev/null || \
  kubectl delete pod crash-demo && sed -i 's/exit 1/sleep 3600/' crash-pod.yaml && kubectl apply -f crash-pod.yaml

## --- Kịch bản 2: ImagePullBackOff ---
kubectl run bad-image --image=nginx:does-not-exist-999
kubectl describe pod bad-image  # xem dòng "Failed to pull image"
kubectl delete pod bad-image

## --- Kịch bản 3: OOMKilled ---
cat > oom-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: oom-demo
spec:
  containers:
  - name: stress
    image: polinux/stress
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "200M", "--vm-hang", "1"]
    resources:
      limits:
        memory: "50Mi"
EOF
kubectl apply -f oom-pod.yaml
sleep 10
kubectl get pod oom-demo             # Status: OOMKilled
kubectl describe pod oom-demo | grep -A5 "Last State"

## --- Công cụ debug nâng cao ---
# Ephemeral container để debug Pod đang chạy (K8s >= 1.23)
kubectl debug -it crash-demo --image=busybox --target=app -- sh

# Sao chép Pod để debug (không ảnh hưởng production)
kubectl debug crash-demo -it --copy-to=crash-demo-debug --image=busybox

✅ Kết quả mong đợi: Xác định đúng nguyên nhân cho cả 3 kịch bản; describe pod cho thấy Events rõ ràng: "Back-off restarting failed container", "Failed to pull image", "OOMKilled".

🧹 Cleanup: kubectl delete pod crash-demo crash-demo-debug bad-image oom-demo 2>/dev/null; true.

3. Tình huống doanh nghiệp thực tế

Bối cảnh

Một fintech startup chạy microservices trên VM thuê, chi phí tăng mạnh khi scale. DevOps team được giao migration lên Kubernetes trong 3 tháng với yêu cầu: zero-downtime, phân quyền theo team (frontend/backend/data), không để developer thấy secret production.

Cách xử lý

  • Namespace strategy: frontend, backend, data, infra — mỗi team có RBAC riêng, không thấy namespace của team khác.
  • Secret management: Dùng External Secrets Operator + HashiCorp Vault (hoặc AWS Secrets Manager) — developer không bao giờ thấy giá trị secret plaintext.
  • Zero-downtime migration: Chạy song song VM + K8s qua LoadBalancer; dùng kubectl rollout với maxUnavailable=0.
  • Ingress routing: Một nginx Ingress Controller điều phối toàn bộ HTTP/HTTPS traffic, TLS termination tập trung, cert-manager tự động gia hạn cert.
  • Kết quả: Chi phí hạ tầng giảm 40% nhờ bin-packing; deployment time từ 45 phút còn 3 phút; incident do misconfiguration giảm vì RBAC ngăn sửa nhầm namespace.

📚 Nguồn tham khảo

Module 14: Docker, Container Image & Registry Module 16: Advanced Kubernetes Operations
Zalo