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

LESSON 4: PRACTICE — SETTING UP CLUSTER AND TOOLS

First practice: test cgroup v2, install containerd 2.0, create cluster with kind/k3d, install and configure k9s, Headlamp. Get familiar with basic kubectl commands.

🔒 DevSecOps — Lesson 4 LESSON 4: PRACTICE — SETTING UP CLUSTER AND TOOL

KUBERNETES: FROM BASIC TO ADVANCED

Module 1: Introduction & Kubernetes Architecture

xdev.asia

Practice 1: Cluster Setup and Tools

This is the first practice exercise in the course. The goal is to turn the theoretical knowledge from previous lessons into practical skills — you will build a complete Kubernetes environment yourself, from testing the system to deploying the dashboard and running cluster discovery commands.

Estimated time: 120 minutes (can be faster if familiar with Linux/terminal)

Exercise output:

  • A 3-node Kubernetes cluster (1 control plane + 2 workers) running on local machine
  • Full set of CLI tools: kubectl, k9s, kubectx/kubens, stern
  • Headlamp dashboard running and accessible
  • Familiarity with commonly used kubectl commands

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 "========================================="

Run the above script and ensure all requirements are met before continuing.

Lab 1: Install containerd 2.0 and Create Kind Cluster

Step 1: Install Docker Engine (if not already available)

kind and k3d both need Docker to run. On macOS, install Docker Desktop. On 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

Step 2: Install kind and create 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 of 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

Step 3: Install kubectl__HTMLTAG_108___
# 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: Installing CLI Tools

Step 1: Install 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

When k9s opens, perform the following operations:

# 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

Step 2: Install kubectx and 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

Step 3: Install 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

Step 4: Setup bash/zsh completion and 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__HTMLTAG_124___

Step 1: Install 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

Step 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

Step 3: Create 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

Step 4: Access 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"

Open browser and access http://localhost:4466. Paste the token to log in. Explore:

  • Nodes: view resource usage, labels, taints
  • Workloads > Pods: see all pods, logs, terminal__HTMLTAG_141___
  • Config > ConfigMaps, Secrets
  • Cluster > Namespaces

Lab 4: Basic kubectl Exploration__HTMLTAG_148___

4.1. Explore 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. Creating First Pod

# 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 the application with 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. Use stern to View 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. Resource Usage Analysis

# 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: Common Errors__HTMLTAG_160___

Error 1: Node is in NotReady state

# 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

Error 2: Pod stuck at Pending__HTMLTAG_164___
# 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

Error 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)

Error 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

Error 5: kind cluster cannot be created

# 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

Lab Cleanup

# 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

Exercise Summary

In this exercise, you completed:

  • Check and confirm prerequisites (cgroup v2, Docker, disk space)
  • Create a 3-node Kubernetes cluster with kind and configure nftables mode
  • Install toolset: kubectl, k9s, kubectx/kubens, stern
  • Deploy and access Headlamp dashboard
  • Practice kubectl commands: get, describe, logs, exec, scale, rollout
  • Getting familiar with troubleshooting Pending pods, CrashLoopBackOff, ImagePullBackOff

From the next article, we dive into Kubernetes objects — starting with Pods, the most basic unit of deployment.