← กลับ
KubernetesTroubleshootingTLSkubeadm

Kubernetes Redeploy ไม่ได้เพราะ Certificate หมดอายุ

kubectl error tls handshake / x509 certificate expired ตอน apply manifest — สาเหตุและวิธีต่ออายุ cert ของ control plane แบบไม่ต้องสร้าง cluster ใหม่

2025-09-22อ่าน 5 นาทีใหม่

อาการที่เจอ

วันหนึ่งจะ 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 ปี

เช็คลิสต์เวลาเจอเหตุการณ์นี้

  1. kubeadm certs check-expiration ดูว่าหมดจริง
  2. ✅ Backup /etc/kubernetes + /var/lib/kubelet/pki
  3. kubeadm certs renew all
  4. ✅ Restart kubelet → static pod ขึ้นใหม่อัตโนมัติ
  5. ✅ Copy /etc/kubernetes/admin.conf~/.kube/config
  6. ✅ Verify ด้วย kubectl get nodes
  7. ✅ ตั้ง alert ป้องกันครั้งหน้า

สรุป

เหตุการณ์นี้เกิดกับ cluster ที่ "deploy แล้วลืมไปนาน" ซึ่งพบบ่อยใน internal cluster, homelab, dev cluster

แก้จริง 10 นาที — แต่ถ้าไม่รู้ว่าต้องดู kubeadm certs คนหา root cause ได้ใช้เวลาเป็นชั่วโมง

ป้องกันโดยตั้ง alert + upgrade cluster ทุก 6-12 เดือน — ไม่มีเหตุผลที่จะปล่อยให้เกิดขึ้นอีก

← ดูบทความอื่น