Basic Kubernetes Part 2 - Pod คืออะไรและวิธีการใช้งานผ่าน Deployment

Basic Kubernetes Part 2 - Pod คืออะไรและวิธีการใช้งานผ่าน Deployment

Pod คืออะไร

ถ้ามองง่ายๆแบบไม่อิงนิยามที่ถูกต้องแบบเป๊ะๆ Pod ก็คือเครื่อง 1 เครื่อง โดยที่เครื่องเครื่องนั้นลง Docker และสามารถ Run container ได้ (บอกไว้ตรงนี้เลยว่านิยามนี้ไม่ถูก แต่อยากอธิบายเพื่อให้เข้าใจง่าย นิยามที่ถูกต้องดูได้จาก : https://kubernetes.io/docs/concepts/workloads/pods/) และในเมื่อมันเป็นเครื่อง ดังนั้นมันจึงมี Volume ซึ่งเราสามารถ Mount volume เข้าไปที่เครื่อง แล้วให้ทุก Container สามารถเข้าถึง Volume นั้นได้ ภาพของ Pod จะเป็นดังตัวอย่างด้านล่าง

ภาพจาก : https://kubernetes.io/docs/tutorials/kubernetes-basics/explore/explore-intro/

จากภาพจะเห็นว่า Pod นั้น Run หลาย Contianer และใน 1 Pod มีหลาย Volume อยู่ และ 1 Pod นั้นจะถูกกำหนด IP ให้สามารถเรียกเข้าไปใช้งานได้

สำหรับ k8s นั้นตัว Pod จะถือเป็นหน่วยที่ถูก Deploy ซึ่งอาจจะถูก Deploy ด้วย Deployment , DaemonSet , StatefulSets ซี่งเดี๋ยวเราค่อยมาทำความเข้าใจกันทีหลัง รู้แค่ว่าตัว Pod จะต้องถูก Deploy

สร้าง Pod ยังไง

ในการสร้าง Pod นั้นสามารถสั่งได้ด้วยคำสั่ง kubectl โดยสามารถสร้างได้ด้วย cmd ตรงๆเลย หรือจะสร้างผ่าน File ที่ทำการบอกว่า pod นั้นมีต้องมีอะไรบ้าง (ไฟล์ที่เราทดลองทำกันใน Part 1) โดยที่เราจะเรียนรู้กันนี่จะเป็นแบบสร้างแบบ File (เขามีภาษาทางการว่า Declarative Configuration Files) เพราะในงานจริงที่เราทำกันนั้น เราไม่สั่ง cmd เป็นคำสั่งๆเพื่อให้ตัว k8s ทำงานให้เพราะมันยากที่จะตรวจสอบว่าสั่งอะไรไปแล้วบ้าง และส่วนใหญ่เราก็ลืมว่าสั่งอะไรไป แต่ถ้าเราทำเป็น Configuration Files นั้นเราจะรู้ว่าเราสั่งสร้างมันยังไง อีกทั้งเมื่อทำเป็น File เราสามารถ Save ลง Git เพื่อเอาไปใช้งานได้อย่างหลากหลายเพิ่มขึ้น ไม่ว่าจะเอาไปทำ CD (Continuous deployment) ทำการตรวจสอบหาการเปลี่ยนแปลงที่ทำให้เกิดปัญหา เป็นต้น

เริ่มสร้าง Pod พื้นฐาน

เนื่องจากต้องเขียน Configuration Files เป็นจำนวนมาก ผมเลยทำ Git ไว้เก็บตัวไฟล์ เผื่อใครขี้เกียจ Copy หรือ พิมพ์ (ผมแนะนำให้ลองพิมพ์เองดูสักหน่อยเพื่อให้เกิดความคุ้นเคยว่ามันต้องมี keyword อะไรบ้างในไฟล์) สามารถไป Clone Repository ได้ที่ Git ตามลิ้งนี้ https://github.com/surapong-taotiamton/training-k8s

สร้างไฟล์ : pod-1.yml จากนั้นใส่เนื้อไฟล์ข้างล่าง

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80

จากนั้นสั่งคำสั่งด้านล่างเพื่อทำการสร้าง Pod

1
kubectl apply -f pod-1.yml

จากนั้นสั่งคำสั่งด้านล่างเพื่อทำการดูข้อมูล Pod ที่เราสร้างขึ้นมา

1
kubectl get pods

จากภาพจะเห็นว่าเราสามารถสร้าง Pod ขึ้นมาได้แล้ว

คราวนี้เราลองมาดูรายละเอียดของ Pod กัน โดยเราจะสั่งโดยใช้คำสั่ง (คำสั่งเหมือนเยอะ แต่ที่ใช้บ่อยๆมันมีแค่ get , apply ,delete , describe logs ซึ่งพอใช้ไปจะรู้เองว่า ถ้าอยากดูให้คำสั่งนี้ อยากสร้าง อยากลบ ใช้คำสั่งนี้ )

1
kubectl describe pod nginx-pod

ขอให้ดูตรงที่ผมครอบแดงไว้ อย่างแรกคือ IP Pods ตัวนี้จะถูก Assign IP ให้เป็น 10.42.0.59 ซึ่ง IP นี้ตัว k8s จะเป็นคนกำหนดให้ ดังนั้นเครื่องคุณกับเครื่องผมจะไม่เหมือนกัน จากนั้นให้คุณลองสั่ง

1
2
3
4
curl <ip ของ pod>
# ของผมคือ 10.42.0.59 เลยได้เป็น

curl 10.42.0.59

ซึ่งจะเห็นว่าสามารถยิง http request ไปหา Pod ที่เราสร้างได้

ส่วนต่อมาที่อยากให้ดูคือ Image เราจะเห็นว่า Image ของ Pod นี้คือ nginx:1.25.1 ซึ่งจะตรงกับที่เรากำหนดไว้ในไฟล์ Configuration

จากทั้งหมดจะเห็นว่าเราสามารถสร้าง Pod ขึ้นมาได้ผ่านไฟล์ pod-1.yml

อธิบายไฟล์ pod-1.yml

ในไฟล์ pod-1.yml จะประกอบด้วย keyword ที่ใช้กำหนด pod ว่ามีต้องมีอะไรบ้าง โดยเราจะค่อยๆอธิบายทีละ keyword เพื่อให้เกิดความเข้าใจ

apiVersion

keyword นี้เป็นตัวบอกว่าตัวการประกาศนี้ต่อจากนี้นั้นใช้ version อะไร โดยที่เขาทำแบบนี้เนี่ยเพราะตัว k8s นั้นต้องรองรับการ deploy ผ่านหลาย version ไม่ใช่พอ Update k8s เป็น version ใหม่ปุ๊ปจะไม่ Support ตัวการประกาศ version เก่าแล้ว ดังนั้นเลยต้องมี apiVersion เพื่อบอกให้ k8s ทราบ

kind

เป็นตัวบอกว่าสิ่งที่สั่งให้ k8s สร้างคืออะไร ซึ่งในไฟล์นี้คือ Pod ก็แปลว่าสั่งให้สร้าง pod

metadata

ส่วนนี้จะเป็นการบอกค่าคุณลักษณะของ pod ตัวนี้ เช่น กำหนดชื่อ กำหนดว่ามันจัดอยู่ในกลุ่มอะไร โดยคุณลักษณะพวกนี้ไม่ได้เกี่ยวกับว่าใช้ Image อะไร ใช้ Ram เท่าไหร่ แต่เป็นคุณลักษณะที่เราอยากเพิ่มเข้าไปเพื่อใช้ในจุดประสงค์เรื่องการจัดการ หรือ ทำอย่างอื่น โดยคุณลักษณะที่เรา set ในตอนนี้คือ

1. name

อันนี้เป็นการบอกว่า pod นี้จะให้เรียกชื่อว่าอะไร

2. labels

ส่วนนี้เป็นเหมือนการแปะ label (ฉลาก) ให้กับ pod นี้ว่ามีค่าอะไรบ้าง ถ้านึกภาพไม่ออกให้นึกว่าคุณอยู่โกดังคัดแยกสินค้า คุณเป็นเจ้าหน้าที่ตรวจสอบสินค้าเพื่อบอกคุณลักษณะของสินคาว่ามีคุณลักษณะอะไร เช่น บอบบาง เป็นอาหาร มีประกัน ส่งด่วน เพื่อให้คนที่รับงานต่อจากคุณสามารถดำเนินการต่อได้ถูก คุณจะทำยังไงให้ง่าย วิธีง่ายๆที่คิดคือคุณสร้าง ฉลากขึ้นมาและแปะไปกับตัวสินค้าเพื่อให้คนที่รับหน้าที่ไปดำเนินการต่อรู้ว่ามันมีคุณลักษณะอะไร เช่น ถ้าส่งด่วน คุณอาจแปะฉลากสีแดงเขียนว่าด่วนไปกับสินค้า คนที่มีหน้าจัดการต่อพอเห็นฉลากนั้นก็จะทราบทันทีว่าส่งด่วน หรือ ถ้าแปะฉลากสีน้ำเงินว่ามีประกัน คนที่รับหน้าที่ดูแลต่อจะทราบว่ามีประกัน ต้องไปทำเอกสารเกี่ยวกับประกัน โดยตัวฉลากนั้นไม่จำเป็นต้องมีอันเดียว เราสามารถแปะได้หลากหลาย เช่น แปะฉลากสีแดง และ สีน้ำเงิน ทำให้รู้ว่า ส่งด่วนและมีประกัน

จากตัวอย่างเราแปะ label ชื่อ app แล้วมีค่าว่า nginx ให้กับ pod นี้

spec

ส่วนนี้จะเป็นการบอกให้ k8s ทราบว่า pod ที่เราสร้างเนี่ยจะใช้ container อะไรบ้าง ใช้ Image อะไร เปิด port อะไร

1. containers

ตรงนี้เป็นการบอกว่า container ใน pod มีอะไรบ้าง (จะเห็นว่าเขาเติม s) จากตัวอย่าง

1
2
3
4
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80

ตรงนี้จะเป็นการบอกว่า container ใน pod ชื่อ nginx-container ใช้ Image nginx:1.25.1 และเปิด port : 80

สร้าง Pod แบบมีหลาย Container

สร้างไฟล์ : pod-2-multiple-container.yml โดยเราจะเห็นว่า pod นี้ต่างจาก pod ที่แล้วคือ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Pod
metadata:
name: pod-multiple-container
labels:
app: test-multiple-conatainer
site: test
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80
- name: whoami-container
image: traefik/whoami
ports:
- containerPort: 81
env:
- name: WHOAMI_PORT_NUMBER
value: "81"
  1. เรากำหนด label มากกว่า 1 ตัวคือมี label
1
2
app: test-multiple-conatainer
site: test
  1. มีการสร้าง Container มากกว่า 1 ตัวให้ Pod ตัวนี้คือ nginx-container , whoami-container

  2. ตัว whoami-container มีการกำหนด Environment โดยกำหนด Environment ชื่อ WHOAMI_PORT_NUMBER ให้กับ whoami-container โดยสั่งผ่าน

1
2
3
env:
- name: WHOAMI_PORT_NUMBER
value: "81"

จากนั้นสั่ง

1
2
kubectl apply -f pod-2-multiple-container.yml
kubectl describe pod pod-2-multiple-container.yml

ลอง curl ไปเช็ค pod ที่คุณสร้างขึ้นมาใหม่ (อย่าลืม IP ของเราไม่เหมือนกันนะครับ) โดยยิงไปที่ port 80 เพื่อดูว่า nginx ทำงานไหม ยิงไปที่ port 81 เพื่อดูว่า whoami ทำงานไหม

1
2
3
4
# ของผม ip ของ pod คือ 10.42.0.62

curl 10.42.0.62:80
curl 10.42.0.62:81

ซึ่งจากภาพเราจะเห็นว่าทั้ง 2 container บน pod เดียวกันสามารถทำงานได้

อยากสร้าง Pod หลายๆตัวที่หน้าตาเหมือนกันทำยังไง

ตอนนี้เราสามารถ pod : nginx เพื่อรองรับ request ได้แล้ว ทุกอย่างดูเหมือนเรียบร้อยแต่ทุกปัญหาก็เกิดขึ้นเมื่อ pod ที่คุณสร้างนี่รับ request ที่มาจากลูกค้าไม่ไหว วิธีที่เราจะจัดการปัญหานี้ในเบื้องต้นคือการ scale out หรือถ้าเทียบกับความเป็นจริงคือเพิ่มสิ่งที่เหมือนกันเข้าไปเพื่อช่วยทำงาน เช่น ถ้าคุณไปซื้อของในห้างสรรพสินค้าแล้วในห้างมีคนรอคิวจ่ายเงินเยอะมากๆ สิ่งที่ห้างจะแก้ปัญหาคนที่รอคิวนานๆได้คือ เปิดช่องจ่ายเงินเพิ่มอีก 1 ช่อง เพื่อให้คนไปจ่ายเงินช่องใหม่ เวลาในการรอคิวก็ลดลง

ด้วยความรู้ที่คุณมีอยู่ตอนนี้คืออยาก scale out ให้มี nginx 3 ตัวคุณจะทำยังไง วิธีการไม่ยากครับคุณสามารถทำได้โดยทำแบบนี้คือ Copy วางแล้วเปลี่ยนชื่อ pod เอาดังด้านล่าง

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
apiVersion: v1
kind: Pod
metadata:
name: scale-nginx-pod-1
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: scale-nginx-pod-2
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: scale-nginx-pod-3
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80
---

ทุกอย่างดูเหมือน ok ครับ แต่ปัญหาคือถ้าผมอยากได้ 5 ตัวล่ะ แล้วอยู่ดีๆผมอยากลดให้มันเหลือ 2 ตัว หรือ 1 ตัวดูล่ะ เรื่องแบบนี้เกิดขึ้นได้ครับ แบบในห้างสรรพสินค้าที่ในช่วงคนเยอะช่องจ่ายเงินอาจเปิดหลายช่อง แต่ช่วงเวลาคนน้อยเขาเปิดแค่ 1 ช่องเท่านั้น ถามว่าวิธีทำมีไหม มีครับ ถ้าอยากลบเราก็แค่สั่ง

1
2
kubectl delete scale-nginx-pod-3
kubectl delete scale-nginx-pod-2

ถ้าสั่งเพิ่มก็ไปสั่งสร้าง pod เพิ่มในไฟล์เอา แต่มันใช่วิธีที่สะดวกไหม ซึ่งก็ขอบอกเลยว่าไม่สะดวก และยุ่งยาก ดังนั้นเพื่อตอบโจทย์การเพิ่มลดตัว pod แบบง่ายๆ จึงมีสิ่งที่เรียกว่า Deployment เกิดขึ้นมาเพื่อช่วยเราแก้ปัญหานี้

Deployment

Deployment คือตัวที่ทำหน้าที่บริหารจัดการสร้าง pod ให้ได้ในลักษณะที่ต้องการ เช่น มีจำนวน pod เท่าไหร่ (นิยามของผมไม่ถูกต้อง 100% นิยามแบบถูกต้อง 100% ดูที่ https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ )

มาลองสร้าง Deployment กันโดยทำการสร้างไฟล์ : deployment-1-basic.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80

จากนั้นสั่งคำสั่งด้านล่างเพื่อสร้าง deployment

1
kubectl apply -f deployment-1-basic.yml

ลองสั่ง get และ describe deployment เพื่อดูว่าเราสามารถสร้างได้สำเร็จหรือไม่และ deployment มีรายละเอียดอะไร

1
2
kubectl get deployment
kubectl describe deployment nginx-deployment

จากภาพจะเห็นว่าเมื่อสั่ง get มี deployment ชื่อ nginx-deployment และมี pod ที่ต้องสร้างภายใต้ deployment นี้คือ 5 ตัว และเมื่อดูรายละเอียดด้วย describe จะพบรายละเอียดว่า deployment นี่สร้าง pod แบบไหน มีจำนวนที่ต้องสร้างเท่าไหร่ และอื่นๆ (จริงๆมีรายละเอียดการสร้างว่าจะค่อยๆ update แบบไหน ค่อยๆสร้างแล้วเปลี่ยน หรือ สร้างหมดแล้วค่อยเปลี่ยน หรือแบบไหน แต่ตอนนี้เรายังไม่ลงรายละเอียด)

คราวนี้เราลองสั่ง

1
kubectl get pods

จะเห็นว่ามี pod ที่ชื่อขึ้นต้นด้วย nginx-deployment โผล่ขึ้นมา 5 ตัว ซึ่ง pod เหล่านี้คือ pod ที่ถูกสร้างขึ้นมาจาก deployment

อธิบายไฟล์ deployment-1-basic.yml

ในส่วนของ apiVersion , kind, metadata ไม่ขออธิบายนะครับเพราะเหมือนกับ pod เราจะมาอธิบายส่วนอื่นๆที่ไ

spec

ตรงนี้คือการบอกว่าเราอยากได้ Deployment แบบไหน

1. replicas

ตรงนี้เป็นการบอกว่าจำนวนสร้าง pod จำนวนกี่ตัว ตรงนี้กำหนดไว้ 5 คือต้องการมี pod 5 ตัว

2. matchLabels

ตรงนี้เป็นการบอกว่าจะจัดการ pod นั้นโดยการ search หาด้วย label อะไร ซึ่งในที่นี้คือ app: nginx ซึ่งค่านี้จะต้องสัมพันธ์กันกับค่า label ในส่วนของ template

3. template

ตรงส่วนนี้เป็นการบอกว่า pod ของเรามีหน้าตาที่จะให้สร้างอย่างไร หากสังเกตดีๆค่าที่อยู่ใน template นั้นคือการ copy ค่าจากส่วน metadata จนถึง spec ใน pod มาใส่ ไม่เชื่อลองไปดูไฟล์ pod-1.yml

1
2
3
4
5
6
7
8
9
10
11
# ส่วน metadata ไปจนถึง spec
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.25.1
ports:
- containerPort: 80

ลองลบ Pod เล่นดูว่าจะเกิดอะไรขึ้น

เรามาลองลบ pod ที่เกิดจากการที่ Deployment สร้างดูว่าจะเกิดอะไรขึ้น

1
2
# kubectl delete pod [ชื่อ pod] ที่ได้มาจากการ get
kubectl delete pod nginx-deployment-59ccdc84fc-rtq7b

จากภาพเราจะเห็นว่าเมื่อเราลบ pod ทิ้งไป แต่เมื่อเราสั่ง get pods มาดูใหม่จะเห็นว่า pod ที่เราลบหายไป (ตัวสีแดง) แต่จะมีตัวใหม่เพิ่มเข้ามา (ตัวสีเขียว) ดังนั้นจะเห็นว่าไม่ว่า pod ของเราจะหายไปด้วยเหตุผลอะไร ตัว deployment จะพยายามสร้างตัว pod ขึ้นมาให้ได้เท่าเดิม

ลองเพิ่มลดจำนวน replicas ดูว่ามีอะไรเปลี่ยนแปลง

ลองเปลี่ยนค่า replicas เป็น 10 จากนั้นสั่ง apply ดูแล้วดูว่าเกิดอะไรขึ้น

จากภาพจะเห็นว่า replicas เพิ่มขึ้นเป็น 10

ลองเปลี่ยน replicas เป็น 1 แล้วลอง apply ดู ซึ่งเมื่อสั่งแล้วจะเห็นว่าตัว pod นั้นเหลือแค่ 1 ตัวแล้ว

สรุป

สำหรับตอนนี้เราได้เรียนรู้ว่า Pod ใน k8s นั้นคืออะไร มีวิธีสร้างผ่าน file ยังไง ลองสร้าง pod ในรูปแบบที่มีหลาย container เรียนรู้ keyword ต่างๆของ pod (ซึ่งบอกเลยว่ายังเหลืออีกหลายอันที่ต้องไปศึกษาเพิ่ม) ไปจนเห็นปัญหาการในการใช้งานจริงว่าถ้าต้อง scale out แล้วมีแค่ pod อย่างเดียวจะเกิดปัญหาอะไร ซึ่งทำให้เราไปใช้ Deployment เพื่อแก้ปัญหานี้

หวังว่าตอนนี้จะทำให้คนที่อ่านได้เข้าใจเกี่ยวกับ Pod และ Deployment ในตอนต่อไปเราจะมาใช้งานตัว Service กัน