อาการที่เจอ
$ kubectl exec -it myapp-abc123 -- sh
error: Internal error occurred: error executing command in container:
failed to exec in container: container is in CONTAINER_EXITED state
หรือ:
$ kubectl exec -it myapp-abc123 -- sh
Error from server: error dialing backend: dial tcp 10.0.0.5:10250: i/o timeout
หรือ:
$ kubectl exec -it myapp-abc123 -- sh
OCI runtime exec failed: exec failed: unable to start container process:
exec: "sh": executable file not found in $PATH
แต่ละ error มาจากคนละสาเหตุ — ต้องอ่าน message ก่อน
ลำดับสิ่งที่ต้องตรวจ
1. Pod ยังรันอยู่หรือเปล่า
kubectl get pod myapp-abc123 -n production
ถ้า:
Running1/1 → pod ทำงานปกติRunning0/1 → ไม่ ready แต่ exec ได้CrashLoopBackOff→ container crash ทุกครั้งที่ startTerminating→ กำลังปิด ไม่รับ exec แล้วCompleted→ จบไปแล้ว exec ไม่ได้
# ดู status ละเอียด
kubectl describe pod myapp-abc123 -n production
2. Container ใน pod ตอนนี้คืออะไร
kubectl get pod myapp-abc123 -o jsonpath='{.status.containerStatuses[*].name}'
ถ้า pod มีหลาย container — ระบุชื่อ:
kubectl exec -it myapp-abc123 -c <container-name> -- sh
ถ้าไม่ระบุ — exec เข้า container แรก
3. Image มี shell มั้ย
Image base ต่างๆ:
alpine→/bin/sh(ash)ubuntu/debian→/bin/bashdistroless→ ไม่มี shell เลยscratch→ ไม่มีอะไรเลย
ถ้าได้:
exec: "sh": executable file not found in $PATH
→ image ไม่มี shell ลอง:
kubectl exec -it myapp-abc123 -- /bin/bash
kubectl exec -it myapp-abc123 -- /bin/ash
kubectl exec -it myapp-abc123 -- /bin/sh
# ถ้า distroless รัน command ตรงๆ
kubectl exec -it myapp-abc123 -- ls /app
4. ใช้ ephemeral debug container
distroless image — ใช้ kubectl debug:
kubectl debug myapp-abc123 -it \
--image=nicolaka/netshoot \
--target=app
--target=app = share namespace กับ container ชื่อ app ใน pod
- เห็น process ของ container เป้าหมาย
- เข้า network เดียวกัน
ทำงานบน K8s 1.23+
5. RBAC permission
$ kubectl exec -it myapp-abc123 -- sh
Error from server (Forbidden): pods "myapp-abc123" is forbidden:
User "developer" cannot create resource "pods/exec"
ตรวจ:
kubectl auth can-i create pods/exec --as=developer -n production
ถ้า no — เพิ่ม role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-exec
namespace: production
rules:
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
ปัญหาที่ deeper
kubelet ตอบไม่ได้
$ kubectl exec -it myapp-abc123 -- sh
Error from server: error dialing backend: dial tcp 10.0.0.5:10250: i/o timeout
apiserver พยายามต่อ kubelet ที่ port 10250 แต่เชื่อมไม่ได้
ตรวจ:
# 1. node ที่ pod อยู่ Ready มั้ย
kubectl get node $(kubectl get pod myapp-abc123 -o jsonpath='{.spec.nodeName}')
# 2. SSH เข้า node ตรวจ kubelet
ssh <node>
sudo systemctl status kubelet
sudo journalctl -u kubelet -n 50
# 3. ตรวจว่า apiserver เห็น kubelet
kubectl get --raw /api/v1/nodes/<node-name>/proxy/healthz
ถ้า kubelet ตาย:
sudo systemctl restart kubelet
Network ระหว่าง apiserver กับ node
# จาก master node
nc -zv <worker-node-ip> 10250
ถ้าเชื่อมไม่ได้ — firewall block port 10250 ระหว่าง master กับ worker
แก้ที่ firewall ให้อนุญาต port 10250 จาก master
Container Runtime ปัญหา
$ kubectl exec -it myapp-abc123 -- sh
error: Internal error: container runtime not ready
ที่ node:
sudo systemctl status containerd
# หรือ
sudo systemctl status docker
restart ถ้าตาย:
sudo systemctl restart containerd
Resource exhaustion
ถ้า node CPU/memory เต็ม — apiserver request timeout
kubectl top node <node-name>
kubectl describe node <node-name> | grep -A 3 -i pressure
ทางเลือก: เข้า node แล้วใช้ crictl
ถ้า kubectl exec ไม่ได้ — SSH เข้า node แล้วใช้ container runtime ตรงๆ:
ssh <node>
# หา container ID
sudo crictl ps | grep myapp
# exec
sudo crictl exec -it <container-id> sh
หรือ Docker:
sudo docker ps | grep myapp
sudo docker exec -it <container-id> sh
วิธีนี้ bypass apiserver — ใช้เมื่อ apiserver / kubelet มีปัญหา
ทางเลือก: kubectl debug
K8s 1.23+ มี kubectl debug:
# สร้าง debug container ใน pod เดิม share namespace
kubectl debug myapp-abc123 -it \
--image=busybox \
--target=app
# clone pod เป็น debug version
kubectl debug myapp-abc123 -it \
--copy-to=myapp-debug \
--container=app \
--image=ubuntu
ดี: distroless image ก็ debug ได้, ทดสอบโดยไม่กระทบ pod จริง
TTY / stdin issue
$ kubectl exec myapp-abc123 -- sh
# (no error but no prompt)
ลืม -it:
kubectl exec -it myapp-abc123 -- sh
-i = interactive (stdin)
-t = TTY allocate
ใช้ pipe:
echo "ls" | kubectl exec -i myapp-abc123 -- sh
Container exited แล้ว
$ kubectl exec myapp-abc123 -- sh
container "app" in pod "myapp-abc123" is waiting to start: ContainerCreating
→ container ยังไม่ start เสร็จ — รอสักครู่
$ kubectl exec myapp-abc123 -- sh
error: container "app" in pod "myapp-abc123" is not running: terminated
→ container ตายไปแล้ว — exec เข้าไม่ได้
ดู log แทน:
kubectl logs myapp-abc123 --previous
Cheat Sheet: เจอ error → ทำอะไร
| Error | สาเหตุ | แก้ |
|---|---|---|
| executable file not found | image ไม่มี shell | ใช้ kubectl debug หรือ command ตรง |
| pods/exec is forbidden | RBAC | ขอ role pod-exec |
| dial tcp ... i/o timeout | apiserver ↔ kubelet | ตรวจ network port 10250 |
| container runtime not ready | containerd/docker ตาย | restart runtime |
| is not running | container ตาย | ดู log แทน, fix crash |
| is waiting to start | ยังไม่ start เสร็จ | รอ หรือดู event |
TLDR
- ตรวจ pod status ก่อน —
kubectl get pod - ตรวจ image มี shell มั้ย — ลอง
/bin/sh,/bin/bash,/bin/ash - ใช้
kubectl debugถ้า distroless - ตรวจ RBAC ถ้า forbidden
- ตรวจ kubelet + network ถ้า i/o timeout
- Bypass ด้วย SSH + crictl ถ้า apiserver/kubelet พัง
สรุป
kubectl exec ใช้ chain ยาว: apiserver → kubelet → container runtime → container ปัญหาเกิดได้ที่ link ใดก็ได้
อ่าน error message เป็นอย่างแรก — ส่วนใหญ่บอก root cause ตรงๆ
ถ้าจริงๆ exec เข้าไม่ได้เลย — kubectl debug หรือ SSH + crictl เป็น backup ที่ยังใช้งานได้ตอนวิกฤต
อ่านต่อ: Troubleshooting K8s Step-by-Step