Pod: หน่วยที่เล็กที่สุดใน Kubernetes
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”Pod คือหน่วยที่เล็กที่สุดที่ deploy ได้ใน Kubernetes container หนึ่งตัวหรือมากกว่านั้นที่รันอยู่บน node เดียวกันเสมอ แชร์ network namespace เดียวกัน และแชร์ volume ได้ด้วยถ้าต้องการ
สิ่งที่ container ใน Pod เดียวกันแชร์กัน
หัวข้อที่มีชื่อว่า “สิ่งที่ container ใน Pod เดียวกันแชร์กัน”container ทุกตัวใน Pod เดียวกันได้ IP address เดียวกันและ network namespace เดียวกัน หมายความว่า container สองตัวใน Pod เดียวกันคุยกันผ่าน localhost ได้เลย ที่ port ไหนก็ได้ที่อีกตัวเปิดรอ ไม่ต้องผ่าน networking ของ cluster เลย container ใน Pod เดียวกันยังแชร์ volume เดียวกันได้ด้วย นั่นคือวิธีที่ sidecar อ่านไฟล์ที่ container หลักเขียนไว้
# From inside the "app" container, a sidecar in the same Pod is reachable on localhostkubectl exec -it app-with-sidecar -c app -- curl -s http://localhost:9090/metricsการแชร์ namespace แบบนี้คือเหตุผลทั้งหมดที่ Pod มีอยู่เป็น concept แยกต่างหาก Pod คือขอบเขตที่ทำให้ “container พวกนี้อยู่ node เดียวกันเสมอและคุยกันผ่าน localhost ได้” เป็นจริงเสมอ container ที่อยู่คนละ Pod ไม่ได้สิ่งนี้ฟรี ๆ ต้องผ่าน Service และ address ที่ route ได้เท่านั้น
Multi-container pattern: sidecar และ init container
หัวข้อที่มีชื่อว่า “Multi-container pattern: sidecar และ init container”สอง pattern นี้ครอบคลุมเกือบทุกเหตุผลที่จะใส่ container มากกว่าหนึ่งตัวใน Pod เดียว
- Sidecar container ผู้ช่วยที่รันคู่กับ container หลักตลอดอายุของ Pod เช่น log shipper ที่ tail log file ของ container หลักแล้วส่งต่อ หรือ proxy ที่จัดการ TLS termination
- Init container container ที่รัน จนจบ ตามลำดับ ก่อนที่ container หลักตัวไหนจะเริ่มทำงาน ใช้บ่อยเพื่อรอให้ dependency พร้อมใช้งาน หรือรัน migration ครั้งเดียวก่อน container หลักจะบูต
apiVersion: v1kind: Podmetadata: name: app-with-sidecarspec: restartPolicy: Always initContainers: - name: wait-for-db image: busybox:1.36 command: ['sh', '-c', 'until nc -z db 5432; do sleep 1; done'] containers: - name: app image: myregistry/app:1.4.0 ports: - containerPort: 8080 - name: log-shipper image: myregistry/log-shipper:2.1.0 volumeMounts: - name: logs mountPath: /var/log/app volumes: - name: logs emptyDir: {}wait-for-db จะบล็อกไม่ให้ Pod เริ่มทำงานจนกว่าจะเชื่อมต่อ database ได้ แล้ว exit สำเร็จ จากนั้น app กับ log-shipper ถึงจะเริ่ม โดยแชร์ network namespace และ volume logs ของ Pod ร่วมกัน
flowchart TB
subgraph pod["Pod app-with-sidecar (one IP, one network namespace)"]
init["initContainer: wait-for-db (runs first, to completion)"] --> app["container: app"]
app -->|localhost| sidecar["container: log-shipper (sidecar)"]
end Lifecycle ของ Pod: phase, state และ restartPolicy
หัวข้อที่มีชื่อว่า “Lifecycle ของ Pod: phase, state และ restartPolicy”Pod เดินผ่านชุด phase เล็ก ๆ ได้แก่ Pending (ถูกรับเข้าระบบแล้วแต่ container ยังไม่ได้รันครบทุกตัว มักติดที่การ schedule หรือดึง image) Running (bound กับ node แล้ว มี container อย่างน้อยหนึ่งตัวกำลังรัน) Succeeded หรือ Failed (container ทุกตัว terminate แล้ว) และบางครั้งก็ Unknown (ดึง state ของ Pod ไม่ได้) ใต้ phase ลงไป container แต่ละตัวมี state ของตัวเอง คือ Waiting, Running หรือ Terminated
สิ่งที่เกิดขึ้นเมื่อ container exit ถูกควบคุมด้วย restartPolicy บน Pod spec Always restart container ที่ exit ทุกครั้งไม่มีสิ้นสุด (ค่า default ใช้กับ service ที่รันระยะยาว) OnFailure restart เฉพาะตอน exit code ไม่เป็นศูนย์ (ใช้กับ Job) และ Never ไม่ restart เลย (ก็ใช้กับ Job บ่อยเหมือนกัน หรือ Pod สำหรับ debug แบบครั้งเดียว)
# Watch a Pod move through its phaseskubectl get pod app-with-sidecar --watch
# Container-level detail: state (Waiting/Running/Terminated), restart count, exit codekubectl describe pod app-with-sidecarทำไมถึงไม่รัน Pod เปล่า ๆ ตรง ๆ ในทางปฏิบัติ
หัวข้อที่มีชื่อว่า “ทำไมถึงไม่รัน Pod เปล่า ๆ ตรง ๆ ในทางปฏิบัติ”Pod ถูกออกแบบมาให้เป็น ephemeral และแทบไม่มีใคร create Pod ตรง ๆ ถ้า kubectl apply Pod เปล่า ๆ แล้ว node ที่ Pod นั้นอยู่ล่ม หรือ container ข้างในพัง เกินกว่าที่ restartPolicy จะช่วยได้ ไม่มีอะไรมา recreate Pod นั้นให้ คือหายไปเฉย ๆ ในทางปฏิบัติคุณแทบจะ create Deployment, StatefulSet หรือ DaemonSet แทนเสมอ controller เหล่านั้นถือ Pod template ไว้ คอย watch state จริงของ cluster และ recreate Pod ทุกครั้งที่ของจริงเบี่ยงไปจากจำนวนที่ต้องการ ส่วนที่เหลือของ module นี้คือ controller พวกนั้น