🎯 MỤC TIÊU BÀI HỌC
Sau khi hoàn thành bài học này, bạn sẽ:
- ✅ Cài đặt containerd container runtime với CRI plugin
- ✅ Cấu hình containerd sử dụng systemd cgroup driver
- ✅ Cài đặt kubeadm, kubelet, kubectl từ official repository
- ✅ Cài đặt crictl cho container debugging
- ✅ Pre-pull sandbox images và verify mọi thứ sẵn sàng
PHẦN 1: CONTAINER RUNTIME — TẠI SAO CONTAINERD?
1.1. Lịch sử Container Runtime trong K8s
Timeline: 2014-2020: Docker → dockershim → containerd (K8s dùng Docker runtime) 2020: K8s 1.20 deprecate dockershim 2022: K8s 1.24 remove dockershim hoàn toàn 2024+: containerd hoặc CRI-O là standard
Container Runtime Interface (CRI): kubelet ─── CRI ──→ containerd ──→ runc ──→ Container │ └──→ CRI-O ──→ runc ──→ Container
1.2. containerd vs CRI-O
| Tiêu chí | containerd | CRI-O |
|---|---|---|
| Maintainer | CNCF (Docker/Moby origin) | CNCF (Red Hat origin) |
| Adoption | Rất rộng (EKS, GKE, AKS mặc định) | OpenShift, RHEL focused |
| Features | Multi-purpose (docker CLI compatible) | K8s-only (lightweight) |
| Image build | Hỗ trợ qua nerdctl/buildkit | Không (cần podman/buildah) |
| Stability | Rất ổn định | Ổn định |
👉 Chọn containerd: Phổ biến nhất, tài liệu nhiều, compatible với mọi K8s distribution.
PHẦN 2: CÀI ĐẶT CONTAINERD
2.1. Cài đặt từ Docker Official Repository
# ============================================ # Chạy trên TẤT CẢ nodes (masters + workers + storage) # ============================================1. Thêm Docker GPG key và repository
install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg |
gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpgecho
"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" |
tee /etc/apt/sources.list.d/docker.list > /dev/null2. Cài đặt containerd
apt update apt install -y containerd.io
3. Verify
containerd --version
Output: containerd containerd.io v2.0.x ...
2.2. Cấu hình containerd
# Tạo default config mkdir -p /etc/containerd containerd config default > /etc/containerd/config.tomlCấu hình quan trọng:
1. Enable SystemdCgroup (BẮT BUỘC cho K8s)
2. Set sandbox image đúng version
Chỉnh sửa config.toml:
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
Verify sandbox image version (phải khớp với K8s version):
grep sandbox_image /etc/containerd/config.toml
Output: sandbox_image = "registry.k8s.io/pause:3.10"
🔬 Deep Dive — Tại sao SystemdCgroup = true?
cgroup driver quản lý resource limits cho containers. Có 2 drivers: cgroupfs và systemd.kubelet sử dụng systemd cgroup driver (mặc định từ K8s 1.22+). containerd PHẢI dùng cùng driver → SystemdCgroup = true.
Nếu mismatch: kubelet (systemd) vs containerd (cgroupfs) → Pods bị OOMKilled bất thường → Resource accounting sai → kubelet restart liên tục
2.3. Cấu hình containerd chi tiết (Optional Tuning)
# /etc/containerd/config.toml — Các section quan trọng:[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.10"
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true # ← CRITICAL
[plugins."io.containerd.grpc.v1.cri".registry]
# Private registry mirrors (nếu cần)
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]
# Harbor internal registry:
# [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.internal.com"]
# endpoint = ["https://harbor.internal.com"]
2.4. Restart và Verify containerd
# Restart containerd systemctl restart containerd systemctl enable containerdVerify containerd running
systemctl status containerd
Output: Active: active (running)
Test containerd CRI
crictl --runtime-endpoint unix:///run/containerd/containerd.sock info
Output: JSON with runtime info
PHẦN 3: CÀI ĐẶT CRICTL
3.1. crictl là gì?
crictl là CLI tool cho CRI-compatible container runtimes. Tương tự docker CLI nhưng cho CRI:
docker ps → crictl ps
docker images → crictl images
docker logs → crictl logs
docker exec → crictl exec
docker inspect → crictl inspect
docker pull → crictl pull
3.2. Cấu hình crictl
# crictl đã được cài cùng containerd.io package # Cấu hình endpoint: cat > /etc/crictl.yaml << 'EOF' runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOFTest
crictl info crictl images
PHẦN 4: CÀI ĐẶT KUBEADM, KUBELET, KUBECTL
4.1. Thêm Kubernetes Repository
# ============================================ # Chạy trên TẤT CẢ nodes # ============================================Kubernetes v1.31 (hoặc latest stable)
KUBE_VERSION="v1.31"
Thêm K8s repository key
curl -fsSL "https://pkgs.k8s.io/core:/stable:/${KUBE_VERSION}/deb/Release.key" |
gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpgThêm K8s repository
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg]
https://pkgs.k8s.io/core:/stable:/${KUBE_VERSION}/deb/ /" |
tee /etc/apt/sources.list.d/kubernetes.listCài đặt
apt update apt install -y kubelet kubeadm kubectl
QUAN TRỌNG: Hold version để tránh auto-upgrade
apt-mark hold kubelet kubeadm kubectl
Verify versions
kubeadm version
Output: kubeadm version: &version.Info{Major:"1", Minor:"31", ...}
kubelet --version
Output: Kubernetes v1.31.x
kubectl version --client
Output: Client Version: v1.31.x
4.2. Enable kubelet
# Enable kubelet service (chưa start vì chưa init cluster) systemctl enable kubeletkubelet sẽ tự start khi kubeadm init/join chạy
Hiện tại nó sẽ crash-loop → bình thường, bỏ qua
4.3. kubectl Bash Completion
# Setup kubectl autocomplete (trên workstation và masters) kubectl completion bash | tee /etc/bash_completion.d/kubectl > /dev/nullAlias cho tiện
echo 'alias k=kubectl' >> ~/.bashrc echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc source ~/.bashrc
Test
k get no[TAB] # → k get nodes
PHẦN 5: PRE-PULL IMAGES
5.1. Pull K8s Images trước khi init
# Xem danh sách images cần thiết cho K8s: kubeadm config images list # Output: # registry.k8s.io/kube-apiserver:v1.31.x # registry.k8s.io/kube-controller-manager:v1.31.x # registry.k8s.io/kube-scheduler:v1.31.x # registry.k8s.io/kube-proxy:v1.31.x # registry.k8s.io/coredns/coredns:v1.11.x # registry.k8s.io/pause:3.10 # registry.k8s.io/etcd:3.5.xPre-pull trên TẤT CẢ control plane nodes (master1, master2, master3):
kubeadm config images pull
Output:
[config/images] Pulled registry.k8s.io/kube-apiserver:v1.31.x
[config/images] Pulled registry.k8s.io/kube-controller-manager:v1.31.x
...
Verify
crictl images | grep k8s.io
💡 Tip: Nếu nodes không có internet access, pull images trên máy có internet, export thành tar, rồi import trên nodes:
# Trên máy có internet: ctr -n k8s.io images export k8s-images.tar $(kubeadm config images list | tr '\n' ' ')Copy sang nodes:
scp k8s-images.tar root@master1:/tmp/
Import trên nodes:
ctr -n k8s.io images import /tmp/k8s-images.tar
PHẦN 6: PRE-FLIGHT CHECK
6.1. kubeadm preflight check
# Chạy preflight checks (dry-run): kubeadm init --dry-run 2>&1 | head -30Hoặc dùng script toàn diện:
#!/bin/bash echo "=== Pre-flight Check ==="
1. containerd
echo -n "containerd: " systemctl is-active containerd && echo "✅" || echo "❌"
2. kubelet enabled
echo -n "kubelet enabled: " systemctl is-enabled kubelet && echo "✅" || echo "❌"
3. Swap disabled
echo -n "Swap disabled: " [[ $(swapon --show | wc -l) -eq 0 ]] && echo "✅" || echo "❌"
4. br_netfilter
echo -n "br_netfilter: " lsmod | grep -q br_netfilter && echo "✅" || echo "❌"
5. ip_forward
echo -n "ip_forward: " [[ $(sysctl -n net.ipv4.ip_forward) -eq 1 ]] && echo "✅" || echo "❌"
6. SystemdCgroup
echo -n "SystemdCgroup: " grep -q "SystemdCgroup = true" /etc/containerd/config.toml && echo "✅" || echo "❌"
7. Images pulled (control plane only)
echo -n "K8s images: " REQUIRED=$(kubeadm config images list 2>/dev/null | wc -l) PULLED=$(crictl images 2>/dev/null | grep -c "registry.k8s.io") echo "${PULLED}/${REQUIRED} pulled"
8. Ports available
for port in 6443 2379 2380 10250 10259 10257; do echo -n "Port $port: " ss -tlnp | grep -q ":$port " && echo "❌ IN USE" || echo "✅ Available" done
echo "" echo "=== Check HAProxy VIP ===" echo -n "VIP reachable: " ping -c 1 -W 2 10.10.20.100 &>/dev/null && echo "✅" || echo "❌" echo -n "HAProxy port 6443: " nc -z -w2 10.10.20.100 6443 &>/dev/null && echo "✅ (will route after API server starts)" || echo "⚠️ Not yet"
💡 KEY TAKEAWAYS
- containerd là standard container runtime, cài từ Docker official repository
- SystemdCgroup = true là BẮT BUỘC — phải match với kubelet cgroup driver
- kubeadm, kubelet, kubectl cài từ pkgs.k8s.io, sau đó
apt-mark holdđể tránh auto-upgrade - Pre-pull images tiết kiệm thời gian init cluster, đặc biệt quan trọng cho air-gapped environments
- Pre-flight checks giúp phát hiện issues trước khi chạy kubeadm init
🎯 BÀI TẬP
Bài tập 1: Cài đặt trên tất cả nodes
- Cài containerd + kubeadm trên tất cả 6 nodes (3 masters + 3 workers)
- Verify SystemdCgroup = true trên mỗi node
- Pre-pull K8s images trên 3 master nodes
- Chạy pre-flight check script, đảm bảo tất cả PASS
Bài tập 2: Air-gapped image transfer
- Export K8s images thành tar file
- Transfer sang 1 node không có internet
- Import và verify images available
📚 BÀI TIẾP THEO
Trong Bài 6: Khởi tạo Kubernetes HA Control Plane đầu tiên, chúng ta sẽ chạy kubeadm init trên master1 với HA configuration, tạo cluster certificate và kubeconfig.