อาการที่เจอ
วันหนึ่งจะ deploy ใหม่ พิมพ์ kubectl apply -f deployment.yaml แล้วได้:
Unable to connect to the server: x509: certificate has expired or is not yet valid:
current time 2026-09-22T10:15:00+07:00 is after 2026-09-21T08:30:00Z
หรือ:
error: failed to download openapi: Get "https://10.0.0.1:6443/openapi/v2?timeout=32s":
remote error: tls: bad certificate
แปลว่า certificate ที่ kubeadm ออกให้ control plane component (apiserver, controller-manager, scheduler, kubelet) หมดอายุ
ทำไมถึงเกิด
kubeadm ออก cert ให้ component ภายใน cluster อายุ 1 ปี (default) — ถ้า cluster นั้นไม่ได้ upgrade เลยตลอด 12 เดือน cert จะหมด
ปกติ kubelet จะ rotate cert ของตัวเองอัตโนมัติ แต่ component อื่น (apiserver, etcd, controller-manager) ไม่ rotate เอง
โดยเฉพาะ home cluster / on-prem ที่ไม่ได้ upgrade เป็นปี — เจอบ่อยมาก
ตรวจสอบก่อน
sudo kubeadm certs check-expiration
ผลลัพธ์:
CERTIFICATE EXPIRES RESIDUAL TIME
admin.conf Sep 21, 2026 08:30 UTC <invalid>
apiserver Sep 21, 2026 08:30 UTC <invalid>
apiserver-kubelet-client Sep 21, 2026 08:30 UTC <invalid>
controller-manager.conf Sep 21, 2026 08:30 UTC <invalid>
etcd-server Sep 21, 2026 08:30 UTC <invalid>
etcd-peer Sep 21, 2026 08:30 UTC <invalid>
front-proxy-client Sep 21, 2026 08:30 UTC <invalid>
scheduler.conf Sep 21, 2026 08:30 UTC <invalid>
<invalid> = หมดอายุแล้ว
วิธีแก้ — Renew certs
ขั้นที่ 1: backup ก่อน
sudo cp -r /etc/kubernetes /etc/kubernetes.bak-$(date +%Y%m%d)
sudo cp -r /var/lib/kubelet/pki /var/lib/kubelet/pki.bak-$(date +%Y%m%d)
ขั้นที่ 2: renew ทุก cert
sudo kubeadm certs renew all
ผลลัพธ์ที่ต้องการ:
certificate embedded in the kubeconfig file for the admin to use ... renewed
certificate for serving the Kubernetes API ... renewed
... ทุกตัว renewed
ขั้นที่ 3: restart control plane
kubeadm ใช้ static pod — restart โดยลบ pod manifest แล้ว kubelet จะ recreate เอง:
# หรือทาง brute force — restart ทุก static pod
sudo systemctl restart kubelet
หรือ "kick" static pod แต่ละตัวด้วยการแตะไฟล์ manifest:
sudo touch /etc/kubernetes/manifests/kube-apiserver.yaml
sudo touch /etc/kubernetes/manifests/kube-controller-manager.yaml
sudo touch /etc/kubernetes/manifests/kube-scheduler.yaml
sudo touch /etc/kubernetes/manifests/etcd.yaml
ขั้นที่ 4: update kubeconfig
/etc/kubernetes/admin.conf ที่ renew แล้ว — copy ทับ kubeconfig ของ user:
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
ขั้นที่ 5: verify
kubectl get nodes
kubectl version
# เช็ควันหมดอายุใหม่
sudo kubeadm certs check-expiration
ทุกอันควรขึ้น EXPIRES อีก 1 ปีข้างหน้า
ถ้าเป็น Multi-master
ทำขั้นข้างบนทุก master node ทีละตัว — อย่าทำพร้อมกันเพราะ etcd ต้องมี quorum
kubelet client cert ไม่ rotate เอง
บางกรณี kubelet ยังใช้ cert เก่า — ลบ cert ตัวเก่าให้ kubelet ขอใหม่:
sudo systemctl stop kubelet
sudo rm -rf /var/lib/kubelet/pki/kubelet-client*
sudo systemctl start kubelet
ตรวจสอบ:
ls -la /var/lib/kubelet/pki/
# ควรเห็น kubelet-client-current.pem ที่เพิ่งสร้าง
ป้องกันไม่ให้เกิดอีก
1. เปิด kubelet auto-rotate (default ใน v1.19+)
/var/lib/kubelet/config.yaml:
serverTLSBootstrap: true
rotateCertificates: true
restart: sudo systemctl restart kubelet
2. ตั้ง alert ก่อน 30 วันที่ cert จะหมด
ใช้ Prometheus + node-exporter หรือเขียน script ง่ายๆ:
#!/bin/bash
# /usr/local/bin/check-k8s-certs.sh
DAYS_LEFT=$(sudo kubeadm certs check-expiration 2>/dev/null \
| awk '/apiserver/ {print $4}' | head -1)
if (( DAYS_LEFT < 30 )); then
curl -X POST $SLACK_WEBHOOK \
-d '{"text":"⚠️ K8s certs expire in '"$DAYS_LEFT"' days"}'
fi
ใส่ใน cron รันสัปดาห์ละครั้ง:
0 9 * * 1 /usr/local/bin/check-k8s-certs.sh
3. ใช้ kubeadm renew เป็นกิจวัตร
upgrade cluster ทุก 6-12 เดือน — kubeadm upgrade apply จะ renew cert ให้ในตัว
ถ้า manage cert เอง (cert-manager)
cluster ที่ใช้ cert-manager จัดการ ingress cert จะไม่กระทบ control plane cert ที่ kubeadm ออก — เป็นคนละชุดกัน อันนี้บทความเน้น control plane cert
cert-manager ดูแลเฉพาะ:
- Ingress TLS
- Service cert (ถ้าตั้ง)
- CA injection
ทางเลือก: เพิ่มอายุ cert default
หลัง v1.22 kubeadm รองรับ extend อายุ cert เป็น 10 ปี:
# สร้าง cluster ใหม่ด้วย config ที่กำหนดอายุ
cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
certificateValidityPeriod: 87600h # 10 ปี
caCertificateValidityPeriod: 87600h
EOF
sudo kubeadm init --config=kubeadm-config.yaml
แต่อันนี้ใช้กับ cluster ใหม่เท่านั้น — cluster ที่มีอยู่แล้วยังคง 1 ปี
เช็คลิสต์เวลาเจอเหตุการณ์นี้
- ✅
kubeadm certs check-expirationดูว่าหมดจริง - ✅ Backup
/etc/kubernetes+/var/lib/kubelet/pki - ✅
kubeadm certs renew all - ✅ Restart kubelet → static pod ขึ้นใหม่อัตโนมัติ
- ✅ Copy
/etc/kubernetes/admin.conf→~/.kube/config - ✅ Verify ด้วย
kubectl get nodes - ✅ ตั้ง alert ป้องกันครั้งหน้า
สรุป
เหตุการณ์นี้เกิดกับ cluster ที่ "deploy แล้วลืมไปนาน" ซึ่งพบบ่อยใน internal cluster, homelab, dev cluster
แก้จริง 10 นาที — แต่ถ้าไม่รู้ว่าต้องดู kubeadm certs คนหา root cause ได้ใช้เวลาเป็นชั่วโมง
ป้องกันโดยตั้ง alert + upgrade cluster ทุก 6-12 เดือน — ไม่มีเหตุผลที่จะปล่อยให้เกิดขึ้นอีก