🎯 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 và cập nhật Ubuntu 24.04 LTS cho tất cả nodes
- ✅ Cấu hình kernel parameters bắt buộc cho Kubernetes
- ✅ Tắt swap vĩnh viễn và hiểu lý do
- ✅ Thiết lập NTP synchronization cho toàn cluster
- ✅ Hardening SSH và cấu hình firewall rules
- ✅ Chuẩn hóa hostname, hosts file và DNS resolution
PHẦN 1: CÀI ĐẶT UBUNTU 24.04 LTS
1.1. Tại sao Ubuntu 24.04 LTS?
- LTS (Long Term Support): 12 năm support (đến 2036 với Ubuntu Pro)
- Kernel 6.8+: Support tốt cho eBPF (Cilium), cgroup v2, io_uring
- systemd 255+: Cải thiện cgroup v2 management
- Widespread adoption: Được test kỹ với K8s, Ceph, và CNCF tools
⚠️ Lưu ý: RHEL 9 / Rocky Linux 9 cũng là lựa chọn tốt cho enterprise. Hướng dẫn này dùng Ubuntu nhưng sẽ ghi chú RHEL commands khi khác biệt.
1.2. Cài đặt cơ bản
# Ubuntu Server 24.04 minimal installation # Chọn options: # - Minimal server (không GUI) # - OpenSSH server # - Disk layout: LVM (theo Bài 2) # - Timezone: Asia/Ho_Chi_Minh (hoặc UTC)Sau khi cài xong, update hệ thống
sudo apt update && sudo apt upgrade -y
Cài đặt essential packages
sudo apt install -y
curl
wget
gnupg
apt-transport-https
ca-certificates
software-properties-common
net-tools
ipvsadm
ipset
jq
bash-completion
vim
htop
iotop
sysstat
lsof
tcpdump
conntrack
socat
nfs-common
open-iscsi
lvm2
treeRHEL 9 equivalent:
sudo dnf update -y
sudo dnf install -y curl wget ...
PHẦN 2: HOSTNAME VÀ DNS RESOLUTION
2.1. Đặt hostname trên mỗi node
# Trên mỗi node, đặt hostname tương ứng # master1: sudo hostnamectl set-hostname master1master2:
sudo hostnamectl set-hostname master2
master3:
sudo hostnamectl set-hostname master3
worker1-3, storage1-3, lb1-2 tương tự
2.2. Cấu hình /etc/hosts trên TẤT CẢ nodes
cat >> /etc/hosts << 'EOF'K8s HA Cluster - Management Network
192.168.10.9 lb1 192.168.10.10 lb2 192.168.10.11 master1 192.168.10.12 master2 192.168.10.13 master3 192.168.10.21 worker1 192.168.10.22 worker2 192.168.10.23 worker3 192.168.10.31 storage1 192.168.10.32 storage2 192.168.10.33 storage3
K8s API Server VIP (Cluster Network)
10.10.20.100 k8s-api.local
EOF
💡 Tip: Trong production, dùng Internal DNS server (CoreDNS hoặc BIND) thay vì /etc/hosts. Bài học này dùng /etc/hosts cho simplicity.
PHẦN 3: KERNEL PARAMETERS CHO KUBERNETES
3.1. Tại sao cần tùy chỉnh kernel?
Kubernetes yêu cầu một số kernel features phải được enable:
| Parameter | Giá trị | Lý do |
|---|---|---|
| net.bridge.bridge-nf-call-iptables | 1 | Bridge traffic qua iptables rules (required cho Service) |
| net.bridge.bridge-nf-call-ip6tables | 1 | IPv6 bridge traffic qua ip6tables |
| net.ipv4.ip_forward | 1 | Forward packets giữa interfaces (pod networking) |
| net.ipv6.conf.all.forwarding | 1 | IPv6 forwarding (nếu dùng dual-stack) |
| fs.inotify.max_user_instances | 8192 | Cho nhiều containers cần inotify (file watching) |
| fs.inotify.max_user_watches | 524288 | Inotify watches per user |
3.2. Cấu hình Kernel Parameters
# Load required kernel modules cat > /etc/modules-load.d/k8s.conf << 'EOF' overlay br_netfilter ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack EOFLoad modules ngay lập tức
modprobe overlay modprobe br_netfilter modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh modprobe nf_conntrack
Verify modules loaded
lsmod | grep -E "overlay|br_netfilter|ip_vs"
# Cấu hình sysctl parameters
cat > /etc/sysctl.d/99-kubernetes.conf << 'EOF'
# ─── Required cho Kubernetes ───
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
# ─── Performance tuning ───
# Tăng conntrack table cho nhiều connections
net.netfilter.nf_conntrack_max = 1048576
# Tăng số file descriptors
fs.file-max = 2097152
fs.nr_open = 1048576
# inotify cho containers
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 524288
# ─── Network performance ───
# Tăng socket buffer sizes
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TCP keepalive (cho long-lived connections)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
# Tăng port range
net.ipv4.ip_local_port_range = 1024 65535
# ─── Memory management ───
vm.max_map_count = 262144 # Required cho Elasticsearch/Kafka
vm.swappiness = 0 # Minimize swap usage
vm.overcommit_memory = 1 # Allow memory overcommit (Redis)
# ─── Ceph OSD tuning (chỉ cần trên storage nodes) ───
# kernel.pid_max = 4194304
# vm.min_free_kbytes = 1048576
EOF
# Apply ngay lập tức
sysctl --system
# Verify
sysctl net.bridge.bridge-nf-call-iptables
# Output: net.bridge.bridge-nf-call-iptables = 1
sysctl net.ipv4.ip_forward
# Output: net.ipv4.ip_forward = 1
PHẦN 4: TẮT SWAP
4.1. Tại sao phải tắt Swap?
Kubelet yêu cầu swap phải tắt (mặc dù K8s 1.28+ có beta swap support). Lý do:
- Swap gây unpredictable latency cho containers
- K8s scheduler tính toán resources dựa trên physical memory
- Swap ẩn OOM issues, khiến debugging khó khăn
- etcd và databases hoạt động rất kém khi swapping
4.2. Tắt Swap vĩnh viễn
# Tắt swap ngay lập tức sudo swapoff -aTắt vĩnh viễn: comment dòng swap trong /etc/fstab
sudo sed -i '/ swap / s/^/#/' /etc/fstab
Verify
free -h | grep Swap
Output:
Swap: 0B 0B 0B
Double verify - không có swap partitions
cat /proc/swaps
Output: (empty)
Nếu dùng swap file:
sudo rm -f /swap.img # Xóa swap file nếu có
PHẦN 5: NTP TIME SYNCHRONIZATION
5.1. Tại sao NTP cực kỳ quan trọng?
- etcd: Sử dụng timestamps cho leader election, yêu cầu clock skew < 500ms
- TLS certificates: Verify dựa trên thời gian, clock sai → cert invalid
- Logs correlation: Log timestamps phải khớp giữa các nodes
- Ceph: MON quorum yêu cầu clock skew < 50ms
5.2. Cấu hình chrony (NTP)
# Cài đặt chrony (thay thế ntpd, tiêu chuẩn cho RHEL/Ubuntu mới) sudo apt install -y chronyCấu hình chrony
cat > /etc/chrony/chrony.conf << 'EOF'
NTP servers - dùng pool gần nhất
pool ntp.ubuntu.com iburst maxsources 4 pool time.google.com iburst maxsources 2 pool time.cloudflare.com iburst maxsources 2
Fallback: GPS hoặc internal NTP server
server ntp.internal.company.com iburst prefer
Record rate of clock drift
driftfile /var/lib/chrony/chrony.drift
Allow NTP client access from cluster network
allow 192.168.10.0/24 allow 10.10.20.0/24
Step clock nếu offset > 1 giây trong 3 updates đầu
makestep 1.0 3
Enable hardware timestamping nếu NIC support
hwtimestamp *
Enable kernel synchronization
rtcsync
Log
logdir /var/log/chrony EOF
Restart chrony
sudo systemctl restart chrony sudo systemctl enable chrony
Verify synchronization
chronyc sources -v
Output:
^* ntp.ubuntu.com 2 6 17 64 +0.153ms 0.421ms 0.312ms
chronyc tracking
Output:
Reference ID : A29FC801 (time.google.com)
Stratum : 2
System time : 0.000000023 seconds fast of NTP time
Kiểm tra trên tất cả nodes: clock skew < 1ms
for host in master{1..3} worker{1..3} storage{1..3}; do echo -n "$host: " ssh $host "chronyc tracking | grep 'System time'" done
PHẦN 6: SSH HARDENING
6.1. Cấu hình SSH an toàn
# Backup cấu hình gốc sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bakTạo cấu hình SSH hardened
cat > /etc/ssh/sshd_config.d/99-hardening.conf << 'EOF'
─── Authentication ───
PermitRootLogin prohibit-password # Chỉ cho SSH key, không password PasswordAuthentication no # Tắt password authentication PubkeyAuthentication yes # Chỉ dùng SSH keys AuthenticationMethods publickey # Enforce public key only
─── Security ───
MaxAuthTries 3 # Max 3 lần thử MaxSessions 10 # Max 10 sessions/connection LoginGraceTime 30 # 30s timeout cho login ClientAliveInterval 300 # Gửi keepalive mỗi 5 phút ClientAliveCountMax 3 # Disconnect sau 3 lần không reply PermitEmptyPasswords no X11Forwarding no # Không cần X11 AllowTcpForwarding yes # Cần cho kubectl port-forward AllowAgentForwarding yes
─── Ciphers (strong only) ───
Ciphers [email protected],[email protected],[email protected] MACs [email protected],[email protected] KexAlgorithms [email protected],[email protected]
─── Access control ───
AllowUsers root admin deploy # Chỉ cho phép users cụ thể
AllowGroups k8s-admins # Hoặc theo group
EOF
Validate config trước khi apply
sudo sshd -t
Output: (no errors)
Apply
sudo systemctl restart sshd
6.2. Setup SSH Key Authentication
# Trên workstation/jump host: # Tạo dedicated key cho K8s cluster (đã làm ở Bài 1) ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/k8s-adminCopy sang tất cả nodes
for host in lb{1,2} master{1..3} worker{1..3} storage{1..3}; do ssh-copy-id -i ~/.ssh/k8s-admin.pub root@${host} done
Test kết nối không cần password
ssh -i ~/.ssh/k8s-admin root@master1 "hostname && date"
PHẦN 7: FIREWALL CONFIGURATION
7.1. UFW cho Control Plane Nodes
# Trên master1, master2, master3:Reset firewall
sudo ufw --force reset sudo ufw default deny incoming sudo ufw default allow outgoing
SSH
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp comment 'SSH from mgmt'
K8s API Server
sudo ufw allow 6443/tcp comment 'K8s API Server'
etcd
sudo ufw allow from 10.10.20.0/24 to any port 2379:2380 proto tcp comment 'etcd'
kubelet API
sudo ufw allow 10250/tcp comment 'kubelet API'
kube-scheduler, kube-controller-manager
sudo ufw allow 10259/tcp comment 'kube-scheduler' sudo ufw allow 10257/tcp comment 'kube-controller-manager'
Cilium
sudo ufw allow 4240/tcp comment 'Cilium health' sudo ufw allow 4244/tcp comment 'Hubble' sudo ufw allow 8472/udp comment 'Cilium VXLAN'
VRRP (keepalived) - nếu LB trên cùng node
sudo ufw allow proto vrrp from 10.10.20.0/24 comment 'keepalived VRRP'
Enable
sudo ufw enable sudo ufw status verbose
7.2. UFW cho Worker Nodes
# Trên worker1, worker2, worker3: sudo ufw --force reset sudo ufw default deny incoming sudo ufw default allow outgoingSSH
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp
kubelet API
sudo ufw allow 10250/tcp
NodePort range
sudo ufw allow 30000:32767/tcp comment 'K8s NodePort'
Cilium
sudo ufw allow 4240/tcp sudo ufw allow 4244/tcp sudo ufw allow 8472/udp
Ceph client (nếu converged mode)
sudo ufw allow from 10.10.20.0/24 to any port 6789 proto tcp comment 'Ceph MON' sudo ufw allow from 10.10.20.0/24 to any port 6800:7300 proto tcp comment 'Ceph OSD'
sudo ufw enable
💡 Alternative: Nhiều production environments dùng nftables hoặc iptables trực tiếp thay vì UFW. Cilium cũng có thể thay thế node-level firewall với Host Policies.
PHẦN 8: CÁC TÙY CHỈNH KHÁC
8.1. Disable Unattended Upgrades (Production)
# Trong production, tự kiểm soát upgrades
sudo apt remove -y unattended-upgrades
# Hoặc cấu hình chỉ security updates:
# sudo dpkg-reconfigure -plow unattended-upgrades
8.2. Cấu hình ulimits
# Tăng limits cho tất cả users/processes cat >> /etc/security/limits.conf << 'EOF' * soft nofile 1048576 * hard nofile 1048576 * soft nproc 65535 * hard nproc 65535 * soft memlock unlimited * hard memlock unlimited EOFĐảm bảo PAM đọc limits.conf
grep -q 'pam_limits.so' /etc/pam.d/common-session ||
echo "session required pam_limits.so" >> /etc/pam.d/common-session
8.3. Disable Transparent Huge Pages
# THP gây latency spikes cho databases (PostgreSQL, Redis) cat > /etc/systemd/system/disable-thp.service << 'EOF' [Unit] Description=Disable Transparent Huge Pages DefaultDependencies=no After=sysinit.target local-fs.target Before=basic.target[Service] Type=oneshot ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install] WantedBy=basic.target EOF
sudo systemctl daemon-reload sudo systemctl enable --now disable-thp.service
Verify
cat /sys/kernel/mm/transparent_hugepage/enabled
Output: always madvise [never]
8.4. cgroup v2 Verification
# Ubuntu 24.04 mặc định dùng cgroup v2 # Verify: stat -fc %T /sys/fs/cgroup/ # Output: cgroup2fs ← cgroup v2 ✅ # Nếu output là tmpfs → cgroup v1, cần migrateNếu cần force enable cgroup v2:
sudo sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"/' /etc/default/grub
sudo update-grub && sudo reboot
PHẦN 9: AUTOMATION — SCRIPT CHUẨN BỊ TẤT CẢ NODES
9.1. Script chuẩn bị node (chạy trên tất cả K8s nodes)
#!/bin/bash # prepare-k8s-node.sh # Chạy script này trên tất cả nodes (masters + workers) set -euo pipefailecho "=== [1/8] Updating system ===" apt update && apt upgrade -y
echo "=== [2/8] Installing packages ===" apt install -y curl wget gnupg apt-transport-https ca-certificates
software-properties-common net-tools ipvsadm ipset jq bash-completion
vim htop iotop sysstat lsof tcpdump conntrack socat nfs-common
open-iscsi lvm2 chrony treeecho "=== [3/8] Loading kernel modules ===" cat > /etc/modules-load.d/k8s.conf << 'MODULES' overlay br_netfilter ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack MODULES
modprobe overlay modprobe br_netfilter modprobe ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh modprobe nf_conntrack
echo "=== [4/8] Configuring sysctl ===" cat > /etc/sysctl.d/99-kubernetes.conf << 'SYSCTL' net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 net.netfilter.nf_conntrack_max = 1048576 fs.file-max = 2097152 fs.inotify.max_user_instances = 8192 fs.inotify.max_user_watches = 524288 net.core.somaxconn = 65535 net.ipv4.tcp_keepalive_time = 600 net.ipv4.ip_local_port_range = 1024 65535 vm.max_map_count = 262144 vm.swappiness = 0 SYSCTL sysctl --system
echo "=== [5/8] Disabling swap ===" swapoff -a sed -i '/ swap / s/^/#/' /etc/fstab
echo "=== [6/8] Configuring chrony NTP ===" systemctl enable --now chrony
echo "=== [7/8] Disabling THP ===" echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag
echo "=== [8/8] Verifying ===" echo "--- Swap status ---" free -h | grep Swap echo "--- cgroup version ---" stat -fc %T /sys/fs/cgroup/ echo "--- Kernel modules ---" lsmod | grep -E "overlay|br_netfilter|ip_vs" | awk '{print $1}' echo "--- Key sysctl values ---" sysctl net.bridge.bridge-nf-call-iptables net.ipv4.ip_forward vm.swappiness
echo "" echo "✅ Node preparation complete! Ready for containerd + kubeadm installation."
9.2. Chạy script trên tất cả nodes
# Từ workstation, distribute và chạy:
for host in master{1..3} worker{1..3} storage{1..3}; do
echo "=== Preparing $host ==="
scp prepare-k8s-node.sh root@${host}:/tmp/
ssh root@${host} "bash /tmp/prepare-k8s-node.sh"
echo "=== $host DONE ==="
echo ""
done
PHẦN 10: VERIFICATION CHECKLIST
10.1. Checklist cho mỗi node
#!/bin/bash # verify-node.sh - Chạy trên mỗi node để verify echo "=== Node: $(hostname) ==="1. OS version
echo -n "OS: "; cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2
2. Kernel version
echo -n "Kernel: "; uname -r
3. cgroup v2
echo -n "cgroup: "; stat -fc %T /sys/fs/cgroup/
4. Swap
SWAP=$(free -m | grep Swap | awk '{print $2}') if [ "$SWAP" -eq 0 ]; then echo "Swap: ✅ Disabled" else echo "Swap: ❌ Still enabled ($SWAP MB)" fi
5. ip_forward
FWD=$(sysctl -n net.ipv4.ip_forward) echo "ip_forward: $([ "$FWD" == "1" ] && echo "✅" || echo "❌") ($FWD)"
6. br_netfilter
BNF=$(sysctl -n net.bridge.bridge-nf-call-iptables 2>/dev/null) echo "bridge-nf-call: $([ "$BNF" == "1" ] && echo "✅" || echo "❌") ($BNF)"
7. NTP sync
SYNC=$(chronyc tracking 2>/dev/null | grep "Leap status" | awk '{print $4}') echo "NTP: $([ "$SYNC" == "Normal" ] && echo "✅" || echo "⚠️") ($SYNC)"
8. Connectivity
for target in master{1..3} worker{1..3}; do if ping -c 1 -W 1 $target &>/dev/null; then echo "Ping $target: ✅" else echo "Ping $target: ❌" fi done
💡 KEY TAKEAWAYS
- Kernel modules overlay và br_netfilter là bắt buộc cho K8s pod networking
- ip_forward = 1 cho phép pod-to-pod traffic đi qua node
- Swap phải tắt vĩnh viễn — kubelet sẽ refuse start nếu swap on
- NTP đồng bộ là critical cho etcd, TLS certificates, và Ceph
- SSH hardening: chỉ key-based auth, disable password login
- Automation script giúp chuẩn bị tất cả nodes nhất quán
🎯 BÀI TẬP
Bài tập 1: Chuẩn bị tất cả nodes
- Chạy prepare-k8s-node.sh trên tất cả 7 VMs (hoặc servers)
- Chạy verify-node.sh trên mỗi node, đảm bảo tất cả checks PASS
- Screenshot kết quả verify-node.sh của 1 master và 1 worker
Bài tập 2: Benchmark NTP
- Kiểm tra clock offset giữa tất cả nodes:
chronyc sources -v - Đảm bảo offset < 1ms giữa tất cả nodes
- Thử ngắt NTP, đổi giờ, và xem chrony tự đồng bộ lại sau bao lâu
Bài tập 3: RHEL 9 variant
- Viết lại prepare-k8s-node.sh cho RHEL 9 / Rocky Linux 9
- Thay apt → dnf, ufw → firewalld
- Test trên 1 VM để verify
📚 BÀI TIẾP THEO
Trong Bài 4: Load Balancer cho Kubernetes API Server, chúng ta sẽ cài đặt keepalived + HAProxy để tạo Virtual IP cho K8s API server, đảm bảo HA cho control plane access.