Chuyển đến nội dung chính

BÀI 4: THỰC HÀNH — THIẾT LẬP CLUSTER VÀ CÔNG CỤ

Bài thực hành đầu tiên: kiểm tra cgroup v2, cài đặt containerd 2.0, tạo cluster với kind/k3d, cài đặt và cấu hình k9s, Headlamp. Làm quen với kubectl commands cơ bản.

🔒 DevSecOps — Bài 4 BÀI 4: THỰC HÀNH — THIẾT LẬP CLUSTER VÀ CÔNG CỤ

KUBERNETES: TỪ CƠ BẢN ĐẾN NÂNG CAO

Module 1: Giới thiệu & Kiến trúc Kubernetes

xdev.asia

Thực Hành 1: Thiết Lập Cluster và Công Cụ

Đây là bài thực hành đầu tiên trong khóa học. Mục tiêu là biến những kiến thức lý thuyết từ các bài trước thành kỹ năng thực tế — bạn sẽ tự tay xây dựng môi trường Kubernetes hoàn chỉnh, từ kiểm tra hệ thống đến deploy dashboard và chạy các lệnh khám phá cluster.

Thời gian ước tính: 120 phút (có thể nhanh hơn nếu đã quen với Linux/terminal)

Kết quả đầu ra của bài thực hành:

  • Một Kubernetes cluster 3-node (1 control plane + 2 workers) chạy trên máy local
  • Bộ CLI tools đầy đủ: kubectl, k9s, kubectx/kubens, stern
  • Headlamp dashboard chạy và accessible
  • Familiarity với các kubectl commands thường dùng

Prerequisites Check

#!/bin/bash
# Chạy script này trước khi bắt đầu

echo "========================================="
echo "  Lab Prerequisites Check"
echo "========================================="

# Check OS
echo ""
echo "[1] Operating System:"
cat /etc/os-release | grep -E "^(NAME|VERSION)="
echo "Kernel: $(uname -r)"

# Check resources
echo ""
echo "[2] Hardware Resources:"
echo "CPU cores: $(nproc)"
echo "Total RAM: $(free -h | awk '/Mem:/{print $2}')"
echo "Free disk: $(df -h / | awk 'NR==2{print $4}')"

# Check cgroup version
echo ""
echo "[3] cgroup Version:"
CGROUP=$(stat -fc %T /sys/fs/cgroup)
if [ "$CGROUP" = "cgroup2fs" ]; then
  echo "✓ cgroup v2 - OK"
else
  echo "✗ cgroup v1 detected - NEED UPGRADE"
  echo "  -> Ubuntu 22.04+ required"
fi

# Check Docker
echo ""
echo "[4] Docker / Container Runtime:"
if command -v docker &> /dev/null; then
  echo "✓ Docker $(docker --version | awk '{print $3}' | tr -d ',')"
else
  echo "✗ Docker not found - required for kind/k3d"
fi

# Summary
echo ""
echo "========================================="
echo "  Requirements:"
echo "  - CPU: 4+ cores (have: $(nproc))"
echo "  - RAM: 8+ GB (have: $(free -h | awk '/Mem:/{print $2}'))"
echo "  - cgroup v2: Required (have: $CGROUP)"
echo "========================================="

Chạy script trên và đảm bảo tất cả requirements được đáp ứng trước khi tiếp tục.

Lab 1: Cài Đặt containerd 2.0 và Tạo Kind Cluster

Bước 1: Cài Docker Engine (nếu chưa có)

kind và k3d đều cần Docker để chạy. Trên macOS, cài Docker Desktop. Trên Linux:

# Ubuntu/Debian - cài Docker Engine
sudo apt update
sudo apt install -y ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io

# Thêm user vào docker group (không cần sudo mỗi lần)
sudo usermod -aG docker $USER
newgrp docker

# Verify Docker chạy được
docker run hello-world

Bước 2: Cài kind và tạo cluster

# Cài kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# Verify
kind version

# Tạo file cấu hình cluster
cat <<'EOF' > ~/k8s-lab-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: k8s-lab
nodes:
  - role: control-plane
    extraPortMappings:
    - containerPort: 30000
      hostPort: 30000
      protocol: TCP
    - containerPort: 30001
      hostPort: 30001
      protocol: TCP
    - containerPort: 8080
      hostPort: 8080
      protocol: TCP
  - role: worker
  - role: worker
networking:
  kubeProxyMode: nftables
EOF

# Tạo cluster (mất khoảng 2-5 phút)
kind create cluster --config ~/k8s-lab-config.yaml
# Expected output:
# Creating cluster "k8s-lab" ...
#  ✓ Ensuring node image (kindest/node:v1.32.x) 🖼
#  ✓ Preparing nodes 📦 📦 📦
#  ✓ Writing configuration 📜
#  ✓ Starting control-plane 🕹️
#  ✓ Installing CNI 🔌
#  ✓ Installing StorageClass 💾
#  ✓ Joining worker nodes 🚜
# Set kubectl context to "kind-k8s-lab"
# You can now use your cluster with:
# kubectl cluster-info --context kind-k8s-lab

# Verify cluster được tạo
kubectl cluster-info --context kind-k8s-lab
kubectl get nodes

Expected output của kubectl get nodes:

NAME                    STATUS   ROLES           AGE   VERSION
k8s-lab-control-plane   Ready    control-plane   2m    v1.32.x
k8s-lab-worker          Ready    <none>          2m    v1.32.x
k8s-lab-worker2         Ready    <none>          2m    v1.32.x

Bước 3: Cài kubectl

# Nếu chưa cài kubectl
KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
curl -LO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/kubectl

# Trên macOS
brew install kubectl

# Kiểm tra kubectl kết nối với cluster
kubectl version

# Xem tất cả pods đang chạy (system pods)
kubectl get pods -A
# Phải thấy các pods: coredns, kindnet (CNI), kube-proxy, etcd, apiserver...

Checkpoint Lab 1

# Chạy các lệnh này để confirm Lab 1 thành công:
echo "=== Lab 1 Checkpoint ==="

echo "Nodes:"
kubectl get nodes -o wide

echo ""
echo "System Pods:"
kubectl get pods -n kube-system

echo ""
echo "Cluster Info:"
kubectl cluster-info

# Tất cả nodes phải Ready, tất cả system pods phải Running

Lab 2: Cài Đặt CLI Tools

Bước 1: Cài k9s

# Linux
curl -LO https://github.com/derailed/k9s/releases/latest/download/k9s_Linux_amd64.tar.gz
tar -xzf k9s_Linux_amd64.tar.gz
sudo mv k9s /usr/local/bin/
rm k9s_Linux_amd64.tar.gz LICENSE README.md

# macOS
brew install k9s

# Verify
k9s version

# Mở k9s (thoát bằng Ctrl+C hoặc :quit)
k9s

Khi k9s mở, thực hành các thao tác sau:

# Trong k9s interface:
# 1. Mặc định bạn đang xem Pods
# 2. Nhấn '0' để xem tất cả namespaces
# 3. Di chuyển lên/xuống bằng mũi tên
# 4. Nhấn 'l' khi chọn pod để xem logs
# 5. Nhấn 'd' để describe pod
# 6. Gõ ':nodes' và Enter để chuyển sang view Nodes
# 7. Gõ ':services' để xem Services
# 8. Gõ ':namespaces' để xem Namespaces
# 9. Nhấn '?' để xem help
# 10. Gõ ':quit' và Enter để thoát

Bước 2: Cài kubectx và kubens

# Linux
sudo git clone https://github.com/ahmetb/kubectx /opt/kubectx
sudo ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
sudo ln -s /opt/kubectx/kubens /usr/local/bin/kubens

# macOS
brew install kubectx

# Verify và thực hành
kubectx
# Output: kind-k8s-lab (với dấu * là context đang dùng)

kubens
# Output: list của tất cả namespaces

# Switch sang kube-system
kubens kube-system
kubectl get pods  # Không cần -n kube-system nữa

# Switch về default
kubens default

Bước 3: Cài stern

# Linux
curl -LO https://github.com/stern/stern/releases/latest/download/stern_linux_amd64.tar.gz
tar -xzf stern_linux_amd64.tar.gz
sudo mv stern /usr/local/bin/
rm -f stern_linux_amd64.tar.gz

# macOS
brew install stern

# Test stern - stream logs từ tất cả coredns pods
stern coredns -n kube-system --tail 10
# Ctrl+C để dừng

Bước 4: Setup bash/zsh completion và aliases

# Thêm vào ~/.bashrc hoặc ~/.zshrc
cat >> ~/.bashrc << 'EOF'

# Kubernetes aliases và completion
source <(kubectl completion bash)
alias k=kubectl
alias kgp='kubectl get pods'
alias kgs='kubectl get services'
alias kgn='kubectl get nodes'
alias kga='kubectl get all'
alias kdp='kubectl describe pod'
alias kl='kubectl logs'
alias kx='kubectx'
alias kns='kubens'
complete -o default -F __start_kubectl k
EOF

source ~/.bashrc

# Zsh users
cat >> ~/.zshrc << 'EOF'
source <(kubectl completion zsh)
alias k=kubectl
alias kgp='kubectl get pods'
alias kgs='kubectl get services'
alias kgn='kubectl get nodes'
alias kga='kubectl get all'
complete -F __start_kubectl k
EOF

source ~/.zshrc

# Test alias
k get nodes

Lab 3: Deploy Headlamp Dashboard

Bước 1: Cài Helm

# Cài Helm 3
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Verify
helm version

# macOS
brew install helm

Bước 2: Deploy Headlamp

# Thêm Headlamp Helm repository
helm repo add headlamp https://headlamp-k8s.github.io/headlamp/
helm repo update

# Kiểm tra chart có available
helm search repo headlamp

# Cài Headlamp
helm install headlamp headlamp/headlamp \
  --namespace kube-system \
  --set replicaCount=1 \
  --wait

# Xem kết quả
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp
kubectl get service -n kube-system headlamp

# Expected output:
# NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
# headlamp   ClusterIP   10.96.xxx.xxx           80/TCP    1m

Bước 3: Tạo Access Token

# Tạo ServiceAccount cho Headlamp
kubectl create serviceaccount headlamp-admin -n kube-system

# Grant cluster-admin (chỉ dùng trong lab/dev environment!)
kubectl create clusterrolebinding headlamp-admin \
  --clusterrole=cluster-admin \
  --serviceaccount=kube-system:headlamp-admin

# Tạo token với thời hạn 24 giờ
HEADLAMP_TOKEN=$(kubectl create token headlamp-admin \
  -n kube-system \
  --duration=24h)

echo "Your Headlamp token:"
echo $HEADLAMP_TOKEN
# Save token này - bạn sẽ cần để đăng nhập

Bước 4: Truy cập Headlamp

# Port-forward (chạy trong background)
kubectl port-forward -n kube-system svc/headlamp 4466:80 &
PORT_FORWARD_PID=$!

echo "Headlamp accessible at: http://localhost:4466"
echo "Port-forward PID: $PORT_FORWARD_PID"
echo ""
echo "Login with the token printed above"

Mở browser và truy cập http://localhost:4466. Paste token để đăng nhập. Khám phá:

  • Nodes: xem resource usage, labels, taints
  • Workloads > Pods: xem tất cả pods, logs, terminal
  • Config > ConfigMaps, Secrets
  • Cluster > Namespaces

Lab 4: Basic kubectl Exploration

4.1. Khám Phá Cluster

# Thông tin cluster
kubectl cluster-info

# Danh sách nodes với thêm thông tin
kubectl get nodes -o wide
# Xem: NAME, STATUS, ROLES, AGE, VERSION, INTERNAL-IP, OS-IMAGE, KERNEL-VERSION

# Describe node để xem chi tiết
kubectl describe node k8s-lab-control-plane
# Quan sát: Conditions, Capacity, Allocatable, System Info, Pods

# Xem tất cả namespaces
kubectl get namespaces

# Xem tất cả pods trong mọi namespace
kubectl get pods -A -o wide

# Xem events của cluster (rất hữu ích khi troubleshoot)
kubectl get events -A --sort-by='.lastTimestamp' | tail -20

4.2. Tạo Pod Đầu Tiên

# Tạo pod nginx đơn giản
kubectl run my-nginx --image=nginx:alpine

# Xem pod đang được tạo
kubectl get pod my-nginx
# Đợi STATUS thành: Running

# Xem logs của pod
kubectl logs my-nginx

# Xem chi tiết pod
kubectl describe pod my-nginx
# Quan sát: Events section - thấy luồng: Scheduled -> Pulled -> Created -> Started

# Exec vào trong pod
kubectl exec -it my-nginx -- sh
# Bên trong container:
ls /usr/share/nginx/html/
cat /etc/nginx/nginx.conf
exit

# Xóa pod
kubectl delete pod my-nginx

4.3. Deploy ứng dụng với Deployment

# Tạo Deployment
cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
  labels:
    app: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello
        image: gcr.io/google-samples/hello-app:2.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "32Mi"
            cpu: "50m"
          limits:
            memory: "64Mi"
            cpu: "100m"
EOF

# Xem deployment được tạo
kubectl get deployments
kubectl get pods -l app=hello-app

# Xem chi tiết rollout
kubectl rollout status deployment/hello-app

# Scale lên 5 replicas
kubectl scale deployment hello-app --replicas=5
kubectl get pods -l app=hello-app
# Phải thấy 5 pods

# Scale xuống 2 replicas
kubectl scale deployment hello-app --replicas=2
kubectl get pods -l app=hello-app

# Expose qua Service
kubectl expose deployment hello-app \
  --port=8080 \
  --type=NodePort \
  --name=hello-svc

kubectl get service hello-svc

4.4. Dùng stern để Xem Logs

# Stream logs từ tất cả pods của hello-app
stern hello-app &

# Tạo traffic để thấy logs
NODE_PORT=$(kubectl get svc hello-svc -o jsonpath='{.spec.ports[0].nodePort}')
echo "NodePort: $NODE_PORT"

# Trên kind, cần port-forward vì NodePort không accessible trực tiếp
kubectl port-forward svc/hello-svc 8888:8080 &

# Gửi requests
for i in {1..5}; do
  curl -s http://localhost:8888
  sleep 0.5
done

# Xem logs đang stream từ stern
# Ctrl+C để dừng stern

4.5. Phân Tích Resource Usage

# Cài metrics-server (nếu chưa có trong cluster)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Patch để hoạt động với kind (disable TLS verification)
kubectl patch deployment metrics-server \
  -n kube-system \
  --type='json' \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

# Đợi metrics-server sẵn sàng
kubectl rollout status deployment/metrics-server -n kube-system

# Xem resource usage
kubectl top nodes
kubectl top pods -A --sort-by=cpu
kubectl top pods -A --sort-by=memory

Troubleshooting Guide: Các Lỗi Thường Gặp

Lỗi 1: Node ở trạng thái NotReady

# Kiểm tra tại sao node NotReady
kubectl describe node  | grep -A 20 Conditions

# Xem kubelet logs (trong kind, exec vào node container)
docker exec -it k8s-lab-worker bash
journalctl -u kubelet -n 50

# Thường gặp: kubelet không start được vì cgroup config
# Kiểm tra cgroup trong container
stat -fc %T /sys/fs/cgroup

# Fix: đảm bảo cgroup v2 trên host trước khi tạo cluster

Lỗi 2: Pod stuck ở Pending

# Xem events để hiểu lý do
kubectl describe pod 
# Tìm phần Events: ở cuối output

# Nguyên nhân thường gặp:
# 1. Insufficient resources
kubectl describe node | grep -A 5 "Allocated resources"

# 2. Image pull error
kubectl get events --field-selector reason=Failed

# 3. PVC not bound
kubectl get pvc

# 4. Node has taint, pod không có toleration
kubectl describe node | grep Taints

Lỗi 3: CrashLoopBackOff

# Xem logs của pod đang crash
kubectl logs  --previous  # --previous để xem logs của lần chạy trước

# Xem logs real-time
kubectl logs  -f

# Kiểm tra exit code và reason
kubectl describe pod  | grep -A 10 "State:"

# Thường gặp:
# - Misconfigured environment variables
# - Missing ConfigMap/Secret
# - Command/entrypoint sai
# - Resource limits quá thấp (OOMKilled)

Lỗi 4: ImagePullBackOff

# Xem chi tiết lỗi
kubectl describe pod  | grep -A 5 "Failed"

# Nguyên nhân:
# 1. Image name/tag sai
# 2. Private registry - không có imagePullSecret
# 3. Network issues trong cluster

# Với kind - load image từ local vào cluster
docker pull nginx:alpine
kind load docker-image nginx:alpine --name k8s-lab

# Verify image được load
docker exec k8s-lab-worker crictl images | grep nginx

Lỗi 5: kind cluster không tạo được

# Xem Docker đang chạy không
docker info

# Kiểm tra disk space
df -h

# Xem Docker logs
journalctl -u docker -n 50

# Xóa cluster cũ nếu còn tồn đọng và tạo lại
kind delete cluster --name k8s-lab
kind create cluster --config ~/k8s-lab-config.yaml

# Reset Docker nếu cần
docker system prune -a  # Cẩn thận: xóa tất cả unused images/containers

Dọn Dẹp Lab

# Xóa resources đã tạo trong bài thực hành
kubectl delete deployment hello-app
kubectl delete service hello-svc

# Dừng port-forward processes
kill $(lsof -t -i:4466) 2>/dev/null  # Headlamp
kill $(lsof -t -i:8888) 2>/dev/null  # hello-app

# Giữ cluster để dùng trong bài tiếp theo
# Để xóa cluster khi không cần:
# kind delete cluster --name k8s-lab

Tóm Tắt Bài Thực Hành

Trong bài thực hành này, bạn đã hoàn thành:

  • Kiểm tra và xác nhận prerequisites (cgroup v2, Docker, disk space)
  • Tạo Kubernetes cluster 3-node với kind và cấu hình nftables mode
  • Cài đặt bộ tools: kubectl, k9s, kubectx/kubens, stern
  • Deploy và truy cập Headlamp dashboard
  • Thực hành các kubectl commands: get, describe, logs, exec, scale, rollout
  • Làm quen với troubleshooting Pending pods, CrashLoopBackOff, ImagePullBackOff

Từ bài tiếp theo, chúng ta đi sâu vào các Kubernetes objects — bắt đầu với Pods, đơn vị triển khai cơ bản nhất.