Kubernetes Zero-2-Hero EP.4 สร้าง Secret ConfigMap และสำรองข้อมูลด้วย PersistentVolume
สวัสดีครับ กลับมาเจอกันอีกครั้งกับ Series “Kubernetes Zero-2-Hero” ซึ่งก็ได้ดำเนินการมาถึง EP.4 กันแล้วนะครับ ใครที่มาถึงจุดนี้แล้วก็ถือว่าไม่ธรรมดาแล้วครับ ก็ขอขอบคุณที่ยังคงติดกันมาจนถึง EP นี้นะครับ ส่วนใน EP.4 นี้ เราจะมาพูดถึงเรื่อง Resouce Type ที่สามารถจัดการกับค่า Config ต่าง ๆ และ การทำพื้นที่สำหรับสำรองข้อมูลให้กับ Pods โดยสิ่งที่เราจะมาแนะนำให้รู้จักในวันนี้คือ
ConfigMap
Secret
Persistent Volume
Persistent Volume Claim
Storage Class
ConfigMap
มาเริ่มกันที่ ConfigMap กันเลยนะครับ
ConfigMap เป็นตัวที่คอยเก็บค่า Config ต่าง ๆ ไม่ว่าจะเป็นค่า Environment Variable (ENV) หรือว่าจะเป็นไฟล์ Config สำหรับ Pods ต่างๆ เราสามารถสร้าง ConfigMap เพื่อเก็บสิ่งเหล่านี้ได้ ซึ่งข้อมูลภายในของ ConfigMap นั้น จะเป็นค่าแบบ Key/Value เมื่อเราสร้าง ConfigMap เอาไว้แล้ว Pods สามารถเรียกใช้ค่า Config หรือไฟล์ที่เราสร้างเก็บไว้ที่ ConfigMap ได้
การสร้าง ConfigMap สามารถสร้างได้ทั้งจาก Command หรือ YAML แต่ในวันนี้เราจะสร้างมันด้วย Command กัน เพราะผมคิดว่ามันสะดวก และทำได้เร็วกว่า
มาเริ่มกันเลยดีกว่านะครับ การสร้าง ConfigMap จากการใช้ KEY/VALUE เหมาะสำหรับการทำ ENV สำหรับนำไปใข้งานใน Pods
# kubectl create configmap <NAME> --from-literal=<KEY>=<VALUE>kubectl create configmap first-config --from-literal=foo=bar --from-literal=foo1=bar1# output
configmap/first-config created
เราสามารถดูได้ว่า ConfigMap ใน Cluster ของเรามีอะไรบ้างได้ดังนี้
kubectl get configmap# output
NAME DATA AGE
first-config 2 79s
ดูรายละเอียดของ ConfigMap
kubectl get configmap first-config -o yaml# output
apiVersion: v1
data:
foo: bar
foo1: bar1
kind: ConfigMap
metadata:
creationTimestamp: "2021-05-18T03:47:16Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:foo: {}
f:foo1: {}
manager: kubectl-create
operation: Update
time: "2021-05-18T03:47:16Z"
name: first-config
namespace: default
resourceVersion: "3161005"
selfLink: /api/v1/namespaces/default/configmaps/first-config
uid: 9eb74b9b-2d78-4d9e-8523-49c22ebeb9d9
จะเห็นใน “first-config” ที่เราสร้างไว้จะมีข้อมูลที่เป็น Key/Value ตามที่เราได้กำหนดไว้
หลายคนอาจจะสงสัยว่าถ้าเรามี Key/Value เยอะมาก ๆ เราต้องคอยมาพิมพ์ Command ยาว ๆ เพื่อสร้างข้อมูลให้กับ ConfigMap รึเปล่า ผมบอกเลยว่า ไม่จำเป็นครับ เพราะเราสามารถสร้าง ConfigMap ได้จากไฟล์ ENV ที่เราได้เตรียมเอาไว้แล้วได้ ดังตัวอย่างนี้
# Create ENV file
echo "COLOR=red\nTYPE=app\nFOO=bar" > env.txtcat env.txt# output
COLOR=red
TYPE=app
FOO=bar# Create ConfigMap from ENV filekubectl create configmap first-env-config --from-env-file=env.txt# output
configmap/first-env-config created
เมื่อเราสร้าง ConfigMap เสร็จแล้วก็ลองมาดูผลลัพธ์กันนะครับ
kubectl get configmap first-env-config -o yaml# output
apiVersion: v1
data:
COLOR: red
FOO: bar
TYPE: app
kind: ConfigMap
metadata:
creationTimestamp: "2021-05-18T03:56:47Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:color: {}
f:foo: {}
f:type: {}
manager: kubectl-create
operation: Update
time: "2021-05-18T03:56:47Z"
name: first-env-config
namespace: default
resourceVersion: "3162671"
selfLink: /api/v1/namespaces/default/configmaps/first-env-config
uid: cfbd5fa6-326d-4dc7-988d-e9d2ae20bc69
จะพบว่าข้อมูลที่อยู่ภายในไฟล์ ENV ที่เราสร้างไว้ทั้งหมด ก็จะเข้าไปอยู่ใน ConfigMap แล้ว
ต่อไปเราจะนำค่าข้อมูลภายใน ConfigMap ไปใช้ใน Pod กัน
ก่อนอื่นสร้างไฟล์ YAML สำหรับการสร้าง Pod
# kubectl run <POD_NAME> --image=<IMAGE_NAME> --dry-run -o yaml > <FILENAME>.yamlkubectl run pod-config --image=nginx --dry-run -o yaml > pod-config.yaml
จากนั้นแก้ไขไฟล์ที่ Command สร้างขึ้นมาให้
# pod-config.yamlapiVersion: v1
kind: Pod
metadata:
labels:
run: pod-config
name: pod-config
spec:
containers:
- image: nginx
name: pod-config
env: # เพิ่มในส่วนของ env เพื่อเพิ่ม ENV ให้กับ container
- name: ENV1 # ชื่อของ ENV
valueFrom: # จะเอาข้อมูลมาจากที่ไหน
configMapKeyRef: # จาก ConfigMap
name: first-config # ชื่อของ ConfigMap
key: foo # key ภายใน ConfigMap
- name: ENV2
valueFrom:
configMapKeyRef:
name: first-config
key: foo1
- name: ENV3
value: bar3 # เราสามารถสร้าง ENV ได้จาก value ที่เป็น Text ธรรมดาได้
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
จากนั้นสร้าง Pod
kubectl create -f pod-config.yaml# output
pod/pod-config createdkubectl get pod pod-config# output
NAME READY STATUS RESTARTS AGE
pod-config 1/1 Running 0 29s
ทดลอง Access เข้าไปยัง Pod เพื่อตรวจสอบดูว่า ภายใน Pod มีค่า ENV ที่เรากำหนดไว้ดังนี้
kubectl exec pod-config — env | grep ENV# output
ENV2=bar1
ENV3=bar3
ENV1=bar
เพื่อลดเวลาการสร้างไฟล์ YAML สำหรับ Pod ที่ต้องการเรียกใช้งานค่าข้อมูลใน ConfigMap หลายค่า เราสามารถใช้วิธีดังนี้เพื่อประหยัดเวลาในการเขียนไฟล์มากยิ่งขึ้น
kubectl run pod-config2 --image=nginx --dry-run -o yaml > pod-config2.yaml
แก้ไขไฟล์ดังนี้
# pod-config2.yamlapiVersion: v1
kind: Pod
metadata:
labels:
run: pod-config2
name: pod-config2
spec:
containers:
- image: nginx
name: pod-config2
envFrom: # จาก env เป็น envFrom
- configMapRef: # นำค่าจาก ConfigMap
name: first-config # ชื่อของ ConfigMap
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
สร้าง Pod
kubectl create -f pod-config2.yaml# output
pod/pod-config2 created
ทดลอง Access เข้าไปยัง Pod เพื่อตรวจสอบ ENV ที่เราสร้างไว้
kubectl exec pod-config2 -- env | grep foo# output
foo=bar
foo1=bar1
จะเห็นว่าค่าใน ConfigMap “first-config” เข้าไปอยู่ภายใน Pod ทั้งหมด
ต่อไปจะเป็นการสร้าง ConfigMap จากไฟล์ เพื่อนำไฟล์เหล่านั้นเข้าไปใช้งานภายใน Pods โดยชื่อไฟล์จะเป็น Key ส่วนข้อมูลจะเป็น Value ภายใน ConfigMap
เริ่มจากการสร้าง ConfigMap จากไฟล์ โดยไฟล์ที่เรานำมาใช้ก็จะเป็นไฟล์ env.txt ที่เราได้สร้างไว้ในก่อนหน้านี้ โดยมีวิธีการสร้าง ConfigMap ดังนี้
# kubectl create configmap <NAME> --from-file=<FILE_NAME>kubectl create configmap first-file-config --from-file=env.txt# output
configmap/first-file-config created
ดูข้อมูลรายละเอียดของ ConfigMap
kubectl get configmap first-file-config -o yaml# output
apiVersion: v1
data:
env.txt: |
COLOR=red
TYPE=app
FOO=bar
kind: ConfigMap
metadata:
creationTimestamp: "2021-05-18T04:38:27Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:env.txt: {}
manager: kubectl-create
operation: Update
time: "2021-05-18T04:38:27Z"
name: first-file-config
namespace: default
resourceVersion: "3169982"
selfLink: /api/v1/namespaces/default/configmaps/first-file-config
uid: 3e2e7381-6361-44da-b042-7f6f88dce5ef
จะเห็นได้ว่า Key ของข้อมูลจะเป็นชื่อไฟล์ ส่วน Value จะเป็นข้อมูลภายในไฟล์
ต่อไปเราจะสร้าง Pod เพื่อนำไฟล์ใน ConfigMap ไปใส่ไว้ภายใน Pod โดยเขียน YAML สำหรับ Pod ดังนี้
# pod-config3.yamlapiVersion: v1
kind: Pod
metadata:
labels:
run: pod-config3
name: pod-config3
spec:
containers:
- image: nginx
name: pod-config3
resources: {}
volumeMounts: # เพิ่มในส่วนของการทำ volume ภายใน Pod
- name: env-config # ชื่อของ volume
mountPath: /opt/env-config/ # Path ที่ต้องการให้ file เข้าไปอยู่
volumes: # สร้าง volume ภายใน Pod
- name: env-config # ชื่อของ volume
configMap: # นำไฟล์มาจาก ConfigMap
name: first-file-config # ชื่อของ ConfigMap
dnsPolicy: ClusterFirst
restartPolicy: Alwayskubectl create -f pod-config3.yaml# output
pod/pod-config3 created
ทดลอง Access เข้าไปยัง Pod เพื่อตรวจสอบว่าไฟล์ได้เข้าไปอยู่ภายใน Pod แล้ว
kubectl exec pod-config3 -- cat /opt/env-config/env.txt# output
COLOR=red
TYPE=app
FOO=bar
จะเห็นว่าไฟล์ “env.txt” ได้เข้าไปอยู่ภายใน Pod และ Path ที่เรากำหนด
Secret
ในส่วนของ Secret นั้นก็จะลักษณะที่คล้ายกับ ConfigMap ที่สามารถใช้เก็บ ENV หรือไฟล์ต่าง ๆ ได้ แต่จะแตกต่างกันตรงที่ว่า Secret นั้นข้อมูลภายในเมื่อเราสร้างขึ้นมาข้อมูลจะถูก Encode ให้เป็น Base64 ซึ่งไม่สามารถอ่านได้ด้วยตาเปล่า ต้องนำไป Decode ก่อนถึงจะอ่านเข้าใจ จึงเหมาะสำหรับการนำไปใช้กับข้อมูลที่เป็นความลับ เช่น Username, Password
มาเริ่มสร้าง Secret กันเลยดีกว่า เริ่มจากการสร้าง Secret จาก Key/Value
# kubectl create secret generic <NAME> --from-literal=<KEY>=<VALUE>kubectl create secret generic first-secret --from-literal=username=username --from-literal=password=password1234# output
secret/first-secret created
เรียกดูข้อมูลภายใน Secret
kubectl get secret first-secret -o yaml# output
apiVersion: v1
data:
password: cGFzc3dvcmQxMjM0
username: dXNlcm5hbWU=
kind: Secret
metadata:
creationTimestamp: "2021-05-18T05:43:15Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:password: {}
f:username: {}
f:type: {}
manager: kubectl-create
operation: Update
time: "2021-05-18T05:43:15Z"
name: first-secret
namespace: default
resourceVersion: "3181330"
selfLink: /api/v1/namespaces/default/secrets/first-secret
uid: 725b7e9c-b1d7-4918-90ea-67987e13a1e1
type: Opaque
จะเห็นได้ว่าข้อมูลที่เรากำหนดไว้ในตอนแรกได้ถูก Encode ให้เป็น Base64
โดยเราสามารถนำไปใช้กับ Pod ได้ดังนี้
# pod-secret.yamlkind: Pod
metadata:
labels:
run: pod-secret
name: pod-secret
spec:
containers:
- image: nginx
name: pod-secret
resources: {}
env:
- name: USERNAME
valueFrom:
secretKeyRef: # เปลี่ยนจาก configMapKeyRef
name: first-secret
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: first-secret
key: password
dnsPolicy: ClusterFirst
restartPolicy: Always
จะเห็นว่าการเรียกใช้งานก็จะคล้ายกับการเรียกใช้ ConfigMap
ทดลองสร้าง Pod จากนั้น Access เข้าไปยัง Pod เพื่อดูค่าของ ENV ภายใน Pod
kubectl create -f pod-secret.yaml# output
pod/pod-secret created# Access to Pod
kubectl exec pod-secret -- env# output
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-secret
USERNAME=username
PASSWORD=password1234
SECOND_POD_SVC_NP_PORT_80_TCP_PROTO=tcp
...
จะเห็นได้ว่ามี ENV ที่เรากำหนดไว้อยู่ภายใน Pod และ Value ที่เคยถูก Encode ไว้ก็จะถูก Decode กลับมาเมื่อเรานำ Value ไปใช้งานใน Pod
Secret ก็สามารถสร้างจากไฟล์เพื่อกำหนดค่า ENV หลายตัวให้กับ Pod ได้ ดังนี้
เริ่มจากสร้างไฟล์สำหรับเก็บค่า ENV
# Create ENV file
echo "USERNAME=admin\nPASSWORD=admin\nTYPE=mobile" > env.txt
cat env.txt# output
USERNAME=admin
PASSWORD=admin
TYPE=mobile
จากนั้นสร้าง Secret จาก ENV ไฟล์
kubectl create secret generic first-env-secret --from-env-file=env.txt# output
secret/first-env-secret created# Get Detail Secret
kubectl get secret first-env-secret -o yaml# output
apiVersion: v1
data:
PASSWORD: YWRtaW4=
TYPE: bW9iaWxl
USERNAME: YWRtaW4=
...
สร้าง Pod เพื่อเรียกใช้ ENV ทั้งหมดภายใน “first-env-secret”
# pod-secret2.yamlapiVersion: v1
kind: Pod
metadata:
labels:
run: pod-secret2
name: pod-secret2
spec:
containers:
- image: nginx
name: pod-secret2
resources: {}
envFrom:
- secretRef: # เปลี่ยนจาก configMapRef
name: first-env-secret
dnsPolicy: ClusterFirst
restartPolicy: Alwayskubectl create -f pod-secret2.yaml# output
pod/pod-secret2 created
Access เข้าไปยัง Pod เพื่อตรวจสอบว่า Pod ได้รับ ENV จาก Secret แล้ว
kubectl exec pod-secret2 -- env# output
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-secret2
PASSWORD=admin
TYPE=mobile
USERNAME=admin
FIRST_POD_PORT_80_TCP_ADDR=10.107.44.192
ก็จะคล้าย ๆ กับ ConfigMap เราจะลองนำไฟล์จาก Secret ไปใส่ไว้ภายใน Pod โดยเริ่มจากการสร้าง Secret จากไฟล์ “env.txt” ที่เคยสร้างไว้ก่อนหน้านี้
kubectl create secret generic first-file-secret --from-file=env.txt# output
secret/first-file-secret created
ตรวจสอบรายละเอียดของ Secret
kubectl get secret first-file-secret -o yaml# output
apiVersion: v1
data:
env.txt: VVNFUk5BTUU9YWRtaW4KUEFTU1dPUkQ9YWRtaW4KVFlQRT1tb2JpbGUK
kind: Secret
...
จะเห็นได้ว่าชื่อไฟล์จะเป็น Key ส่วน Value ก็จะเป็นข้อมูลภายในไฟล์ที่ถูก Encode ไว้
จากนั้นสร้าง Pod เพื่อนำไฟล์จาก Secret ไปใส่ไว้ภาย Pod
# pod-secret3.yamlapiVersion: v1
kind: Pod
metadata:
labels:
run: pod-secret3
name: pod-secret3
spec:
containers:
- image: nginx
name: pod-secret3
resources: {}
volumeMounts: # ทำ VolumeMount เหมือนกับ ConfigMap
- name: env-secret
mountPath: /opt/env-secret
volumes:
- name: env-secret
secret: # เปลี่ยนจาก ConfigMap เป็น Secret
secretName: first-file-secret # เปลี่ยนจาก name เป็น secretName
dnsPolicy: ClusterFirst
restartPolicy: Alwayskubectl create -f pod-secret3.yaml# output
pod/pod-secret3 created
จากนั้น Access เข้าไปยัง Pod เพื่อดูว่าไฟล์ได้ถูกนำไปวางไว้ภายใน Pod แล้ว
kubectl exec pod-secret3 -- cat /opt/env-secret/env.txt# output
USERNAME=admin
PASSWORD=admin
TYPE=mobile
Secret สามารถใช้สร้างเป็น Credential สำหรับการใช้งาน Pull Image จาก Private Registry ที่จำเป็นต้องทำการยืนยันตัวตนก่อนถึงจะใช้งาน Image ได้ โดยเราสามารถสร้างได้ดังนี้
kubectl create secret docker-registry <SECRET-NAME> --docker-server=<REGISTRY-SERVER> --docker-username=<USERNAME> --docker-password=<PASSWORD> --docker-email=<EMAIL>
นำไปใช้ในไฟล์ YAML
apiVersion: v1
kind: Pod
metadata:
name: demo-private-registry
spec:
containers:
- name: demo
image: <PRIVATE_IMAGE>
imagePullSecrets:
- name: <SECRET_NAME>
ต่อไปจะเป็นการสร้าง Secret สำหรับการเก็บ Key และ Cert สำหรับการทำ Ingress แบบ HTTPs ซึ่งเราก็ได้ใช้งานไปแล้วใน EP ก่อนหน้านี้ วิธีสร้างก็มีดังนี้
kubectl create secret tls <SECRET-NAME> --key=<TLS.KEY> --cert=<TLS.CERT>
นำไปใช้ในไฟล์ YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress-tls
spec:
tls:
- hosts:
- demo.example.com
secretName: <SECRET_NAME>
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-svc
port:
number: 80
Persistent Volume
ถึงแม้ว่า Pods จะมี Volumes อยู่ภายในตัวของ Pods เองแล้วก็ตาม แต่ Volume ภาย ใน Pod นั้นสามารถหายไปได้เมื่อ Pod นั้นมีปัญหาแล้วถูกลบออกไป จึงจำเป็นต้องมี Persistent Volume (PV) เป็นเครื่องมือสำหรับการจองพื้นที่บน Disks จริง ๆ เพื่อให้ Pods สามารถใช้พื้นที่ตรงนั้นในการเก็บข้อมูลสำรองได้ โดยเราสามารถสร้าง PV ได้ดังนี้
# pv1.yamlapiVersion: v1
kind: PersistentVolume # Resource Type
metadata:
name: pv1 # ชื่อของ PV
spec:
storageClassName: demo # ชื่อของ StorageClass
capacity:
storage: 1Gi # ขนาดของ PV
accessModes:
- ReadWriteOnce # Access Mode
hostPath:
path: "/opt/k8s/data" # Path บนเครื่องที่จะให้เป็นพื้นที่เก็บข้อมูลkubectl create -f pv1.yaml# output
persistentvolume/pv1 created
จากนั้นเมื่อสร้าง PV เรียบร้อยแล้วให้ลองเรียก PV ใน Cluster ออกมาดู
kubectl get pv# output
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Retain Available demo 98s
ตอนนี้เรามี PV แล้ว แต่ว่า Pods นั้นไม่สามารถเรียกใช้งาน PV ได้โดยตรง Pods จะเข้าถึงพื้นที่ใน PV ได้ด้วย Persistent Volume Claim
Persistent Volume Claim
เนื่องจาก Pods นั้นไม่สามารถเข้าถึงพื้นที่ของ PV ได้โดยตรง จึงจำเป็นต้องมี Persistent Volume Claim (PVC) เป็นตัวกลางในการขอใช้งานพื้นที่จาก PV โดยเราสามารถสร้าง PVC ได้ ดังนี้
# pvc1.yamlapiVersion: v1
kind: PersistentVolumeClaim # Resource Type
metadata:
name: pvc1 # ชื่อของ PVC
spec:
storageClassName: demo # ชื่อของ StorageClass ให้ตรงกับ PV ที่เราได้สร้างไว้
accessModes:
- ReadWriteOnce # Access Mode ให้ตรงกับ PV ที่เราสร้างไว้
resources:
requests:
storage: 200Mi # พื้นที่ๆจะขอใช้งานkubectl create -f pvc1.yaml# output
persistentvolumeclaim/pvc1 created
เรียกดู PVC ใน Cluster
kubectl get pvc# output
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc1 Bound pv1 1Gi RWO demo 37s
เมื่อเราลองเรียกดู PV อีกครั้งจะพบว่า PV ได้ถูกขอใช้พื้นที่ไปแล้ว
kubectl get pv# output
AME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Retain Bound default/pvc1 demo 10m
จากนั้นลองสร้าง Deployment ขึ้นมา 2 Deployment โดย Deployment ทั้งสองอันจะแตกต่างกันตรงที่ว่าอันนึงได้ทำการสำรองข้อมูลด้วย PVC ส่วนอีกหนึ่งอันไม่มีการทำสำรองข้อมูลเอาไว้
Deployment A
Deployment A จะมีการทำสำรองข้อมูลด้วย PVC
# deploy-a.yamlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: deploy-a
name: deploy-a
spec:
replicas: 1
selector:
matchLabels:
app: deploy-a
strategy: {}
template:
metadata:
labels:
app: deploy-a
spec:
volumes: # ส่วนของ Volume
- name: myvol # ชื่อ Volume
persistentVolumeClaim: # เรียกใช้งาน PVC
claimName: pvc1 # ชื่อของ PVC
containers:
- image: nginx
name: nginx
volumeMounts:
- name: myvol
mountPath: /usr/share/nginx/html
resources: {}kubectl create -f deploy-a.yaml# output
deployment.apps/deploy-a created
Deployment B
Deployment B ไม่มีการทำสำรองข้อมูล
# deploy-b.yamlapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: deploy-b
name: deploy-b
spec:
replicas: 1
selector:
matchLabels:
app: deploy-b
strategy: {}
template:
metadata:
labels:
app: deploy-b
spec:
containers:
- image: nginx
name: nginx
resources: {}kubectl create -f deploy-b.yaml# output
deployment.apps/deploy-b created
ทดลองตามขั้นตอนดังนี้ทั้งสอง Deployment
# Get pods
kubectl get pod# output
NAME READY STATUS RESTARTS AGE
deploy-a-669b5b58b6-g7nrw 1/1 Running 0 6m17s
deploy-b-5c846bb6fb-9w6vz 1/1 Running 0 4m15s
deployment-hpa-7df4d6fd59-g69mf 1/1 Running 0 23h
first-deployment-7fb6db4798-24bhq 1/1 Running 2 3d22h
...# Access เข้าไปยัง Pods ที่สร้างจาก Deployment A,B เพื่อทดลองสร้างไฟล์
kubectl exec <POD_NAME> -- sh -c "echo test > /usr/share/nginx/html/test.html"# Access ข้าไปยัง Pods ที่สร้างจาก Deployment A,B ดูว่าไฟล์ถูกสร้างขึ้นมาแล้ว
kubectl exec <POD_NAME> -- cat /usr/share/nginx/html/test.html# output
test# ลบ Pods ที่สร้างมาจาก Deployment A,B
kubectl delete pod <POD_NAME># เมื่อลบ Pods ไปแล้ว Pods จะถูกสร้างขึ้นมาใหม่
# ทดลองอ่านไฟล์ที่ถูกสร้างไว้่อีกครั้งในทั้งสอง Pods
# จะพบว่าผลลัพธ์ที่ออกมาจะต่างกัน# output deploy-a
test# output deploy-b
cat: /usr/share/nginx/html/test.html: No such file or directory
command terminated with exit code 1
หากทดลองตามขั้นตอนแล้ว จะพบว่า Pods ที่ไม่ได้ทำ Persistent Volume จะไม่สามารถนำข้อมูลเดิมที่เคยมีอยู่ภายใน Pods กลับมาใช้งานได้
Storage Class
ทุกครั้งที่เราจะทำ Persistent Volume ให้กับ Pods เราต้องคอยสร้าง PV ก่อนสร้าง PVC ก่อนตลอด จึง Storage Class (SC) ขึ้นมาช่วยในเรื่องของการสร้าง PV ให้อัตโนมัติเมื่อมีการสร้าง PVC ที่นี้เราก็ไม่จำเป็นต้องสร้าง PV เองอีกต่อไป
ซึ่งตัว SC หน้าที่การติดตั้งถูกทำโดย Admin ที่คอยจัดการกับ Cluster ซึ่งก็แล้วแต่ว่า Cluster นั้น Admin ได้สร้าง SC ไว้ให้หรือไม่ แต่ใน Local Cluster ของเรานั้นได้ทำการติดตั้งตัว SC ไว้ให้เรียบร้อยแล้ว สามารถเรียกดูได้ดังนี้
kubectl get sc# output
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hostpath (default) docker.io/hostpath Delete Immediate false 42d
มาทดลองสร้าง PVC จาก SC กัน เริ่มจากการสร้างไฟล์ YAML สำหรับ PVC ขึ้นมาดังนี้
# pvc-sc.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-sc
spec:
storageClassName: hostpath # ระบุชื่อ SC ให้ตรงกับชื่อ SC ที่เรามีอยู่
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Mi # พื้นที่ๆจะขอใช้งานkubectl create -f pvc-sc.yaml# output
persistentvolumeclaim/pvc-sc created
เรียก PVC และ PVC ขึ้นมาดู
kubectl get pv,pvc# output
persistentvolume/pv1 1Gi RWO Retain Bound default/pvc1 demo 61m
persistentvolume/pvc-6279a5cf-b5a3-4f21-88b8-73265c949088 200Mi RWO Delete Bound default/pvc-sc hostpath 69sNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc-sc Bound pvc-6279a5cf-b5a3-4f21-88b8-73265c949088 200Mi RWO hostpath 69s
persistentvolumeclaim/pvc1 Bound pv1 1Gi RWO demo 52m
จะพบ PV นั้น จะถูกสร้างขึ้นมาโดยอัตโนมัติ เมื่อเราสร้าง PVC
จากนั้นเราสามารถนำ PVC ไปใช้งานใน Pods ได้เหมือน PVC ทั่วไปได้เลย
Conclusion
- ConfigMap เป็นเครื่องมือที่เอาไว้จัดการเรื่องของการนำ ENV ไปใช้ภายใน Pods และยังสามารถสร้าง ConfigMap จากไฟล์ เพื่อนำไฟล์นั้นนำเข้าไปไว้ภายใน Pods ได้
- Secret การทำงานจะคล้าย ๆ กับ ConfigMap แต่ Secret นั้นข้อมูลภายในจะถูก Encode เป็น Base64 โดยสามารถนำไปใช้ใน Pods ได้เหมือนกับ ConfigMap ทุกอย่าง และ Secret ยังสามารถสร้าง Credential Secret ที่นำเอาไปใช้ในการ Pull Image ที่ต้องได้รับอนุญาติก่อนถึงจะสามารถใช้งานได้ และสุดท้ายสามารถสร้าง Secret สำหรับการนำไปทำ Ingress แบบ HTTPs ได้อีกด้วย
- Persistent Volume (PV) เป็นเครื่องมือในการจองพื้นที่กับ Disks จริง ๆ เพื่อให้ Pods ได้ใช้พื้นที่สำหรับสำรองข้อมูล
- Persistent Volume Claim (PVC) เรามีพื้นที่จาก PV แล้ว แต่ว่า Pods ไม่สามารถใช้งานพื้นที่จาก PV ได้โดยตรง จึงจำเป็นต้องมี PVC เป็นตัวกลางในการขอใช้งานพื้นที่
- Storage Class เป็นเครื่องมือที่จะทำให้เราสามารถสร้าง PVC ได้ง่ายขึ้น โดยเราสามารถสร้าง PVC ได้เลย โดยไม่ต้องสร้าง PV ก่อน โดยที่ Storage Class จะสร้าง PV ให้เองอัตโนมัติเมื่อเราสร้าง PVC
เป็นอย่างไรกันบ้างครับ ก็จบกันไปแล้วนะครับสำหรับ EP.4 ซึ่งถ้าได้เรียนมาถึงจุดนี้แล้วก็สามารถทำงานกับ Kubernetes Cluster ในเบื้องต้นได้แล้วครับ แต่สำหรับใครที่อยากจะรู้ และเข้าใจมันมากขึ้นกว่านี้ก็สามารถไปศึกษาหาความรู้เพิ่มเติมได้เลยครับ ยังมีคนสอนในเรื่องนี้เยอะแยะมากมาย ยังไงก็ลองเข้าไปศึกษาเพิ่มเติมดูนะครับ ส่วน Blog ของผม EP ถัดไป จะเป็น EP สุดท้ายแล้วนะครับ ซึ่ง EP สุดท้าย เราก็จะมาพูดถึงเรื่องของ Good to Know ของ Kubernetes ซึ่งผมก็เตรียมไว้อยู่ 3 เรื่องด้วยกันคือ Liveness, Readiness และ เรื่องของการจัดการ Version ของ Deployment ก็อย่าลืมรอติดตามกันนะครับ
เพื่อนๆสามารถติดตามกันได้ที่ https://www.facebook.com/sirisoft แล้วพบกันใหม่เร็วๆนี้ ขอบคุณครับ 👋🏻👋🏻👋🏻
ALL EPISODE
EP.1 มารู้จักกับ Kubernetes พร้อมหลักการทำงาน ไปจนถึงวิธีการติดตั้งบนเครื่อง Local !!
EP.2 ทำความรู้จัก Resource Type และ การ Deploy Application บน Kubernetes
EP.3 สร้าง Service Ingress และการทำ Horizontal Pod Autoscaler
EP.4 สร้าง Secret ConfigMap และสำรองข้อมูลด้วย PersistentVolume
EP.5 สร้าง Health Check ด้วย Liveness Readiness และ การใช้งาน Rollout