Basic Kubernetes Part 5 - ConfigMap และ Secret
ตอนนี้เรามาทำความทำความรู้จัก ConfigMap และ Secret กันว่าคืออะไร
รูปแบบการ Config ที่เป็นที่นิยม
สิ่งหนึ่งที่ขาดไม่ได้ของ Application คือการ Configuration เช่น nginx ต้องทำการ Config เปลี่ยน Endpoint ของ Reverse proxy หรือตัว Application เองต้องการกำหนดตัว Connection Pool ของ Database ให้มากขึ้นหรือลดลง หรือ แก้ไข Maximum file size ที่จะ Upload เข้ามาใน Application การ Config
Application นั้นนิยมทำการ Config ผ่านไฟล์ แต่ในปัจจุบันที่ใช้ Container กันนั้นเปลี่ยนมา Config ผ่านตัว Environment แทน เนื่องจากเราไม่อยากเข้าไปยุ่งกับตัว Volume เพราะเมื่อไหร่ที่ยุ่งกับ Volume จะมีข้อจำกัดต่างๆ เช่น Volume นี้ต้อง Mount จากไหน อ่านได้จากกี่ Node แต่ถ้าเป็น Environment นั้น ตัวสร้างสามารถกำหนดค่า Environment ผูกไปกับ Container ตอนสร้างได้เลย ซึ่งจะไป Run ที่ Node ก็ได้ ดังนั้นการ Config ผ่าน Environment จึงเป็นที่นิยม
เพื่อให้ทำการ Config ทั้ง 2 แบบได้ ทาง k8s ก็ได้ทำการสร้างสิ่งอำนวยความสะดวกในการทำการ Config ขึ้นมาซึ่งนั่นก็คือ ConfigMap โดย ConfigMap นั้นสามารถ Mount volume ไปเป็น File ได้และความพิเศษของมันก็คือมันสามารถถูกเข้าถึงได้จากทุก Node ใน Cluster ของ k8s ดังนั้น ConfigMap จึงแก้ปัญหาการ Config แบบ File ได้
ConfigMap คืออะไร
ConfigMap คือ Object แบบ KeyValue ที่ตัว Pods สามารถเข้าถึงและเอาไปเป็น Environment เอาไป Mount Volume เป็นไฟล์ (นิยามเต็มไปอ่านที่ : Link )
ตัวอย่างไฟล์ Configuration ทั้งหมดในตอนนี้อยู่ที่ Link
สร้าง ConfigMap กัน
สร้างไฟล์ basic-configmap.yml
1 | apiVersion: v1 |
จากนั้นสั่ง apply และลอง get และ describe ตัว configMap ดู
จะเห็นว่ามี ConfigMap ที่เราสร้างโผล่ขึ้นมาและเมื่อ Describe ดูค่าแล้วเราจะเห็นค่าที่เรากำหนดไว้กับ key ต่างๆเลย เช่น key : config1 มี value : data config 1
อธิบายไฟล์ basic-configmap.yml
ส่วนของ apiVersion , kind , metadata ไม่ขออธิบายนะครับเพราะเหมือนกับ Pod , Deployment , Service
data
ตรงนี้จะเป็นการประกาศ Key , Value ของ ConfigMap โดยตัวอย่างจะเป็น
1 | config1: "data config 1" |
ซึ่งหมายความว่า key : “config1” มี value : “data config 1” key : config2 มี value : “data config 2” โดยเราสามารถประกาศตัว key value ได้ตามใจเพียงค่าอย่าให้ key ซ้ำกันก็พอ
เอา ConfigMap ไปเป็น Environment
จากตัวอย่างที่เราทำมาเราจะทำการ set environment ของ Pod ผ่านตรง env เช่นตัวอย่างด้านล่าง
1 | apiVersion: v1 |
ซึ่งถ้า Config env มันเยอะตรงนี้มันก็จะดูมากมายเต็มไปหมด เวลา Config อะไรก็ต้องมาแก้การ Define Pod ตลอด ดังนั้นถ้าเราแยกส่วน Config ออกมาเวลาแก้ไขก็แก้ที่ Config เลยน่าจะดีกว่า (ทีม Config จะได้ยุ่งแค่ Config ไฟล์เดียวไม่ต้องมายุ่งกับการประกาศ Pod ) ซี่งเราสามารถทำได้โดยประกาศแบบนี้
1 | # whoami-pod-002.yml |
เพื่อให้ง่ายต่อการเช็ค Environment ผมขอใช้ตัว image : whoami เพราะมันมี api ให้เรายิงไปดู Environment ที่ถูก set ไว้ให้กับ container ได้ (สามารถดูรายละเอียดได้ที่ : Link ) ดังนั้นผมขอสร้าง Service เพื่อเรียกผ่าน Browser นะครับ จะได้ไม่ต้องมานั่ง Describe ตัว Pod หา IP แล้วยิง
1 | # whoami-service.yml |
ให้เราเปิด Browser แล้วเปิด URL : http://<ip ของเครื่องที่ run k8s>:32020/api?env=true (ของผมเป็น http://192.168.156.101:32020/api?env=true)
จากภาพจะเห็นว่าเมื่อยิงไปจะได้ json response กลับมาจะมีส่วนที่เป็น environment กลับมาดังภาพ ซึ่งนั่นแปลว่าตัว Pod whoami ถูก Set environment จาก ConfigMap จริงๆ
อธิบายไฟล์ whoami-pod-002.yml
ในไฟล์นี้จะมีส่วนที่เพิ่มเติมมาคือ envFrom
envFrom
ตรงส่วนนี้จะเป็นการบอกว่าจะเอา Environment มาจากไหน
1 | envFrom: |
โดยจากตัวอย่างเนี่ยเราบอกว่าให้เอามาจาก configMap โดยบอกจาก keyword : configMapRef โดยเอามาจาก ConfigMap ชื่อ basic-configmap ซึ่งการประกาศแบบนี้คือเอาทุกค่าใน ConfigMap มาใส่ในนี้เลย
อยาก Set แค่บาง Environment ล่ะ
ในส่วนที่แล้วเราลอง Set environment ผ่าน ConfigMap ซึ่งเป็นการเอามาใส่ทั้ง ConfigMap แต่บางกรณีเราไม่อยากเอาค่าทุกค่าจาก ConfigMap ไปเป็น environment เราอยากได้แค่บางค่าเราจะทำยังไง แน่นอนว่านี่คือปัญหาทั่วไปที่ทุกคนอยากได้ซึ่ง k8s ก็ทำให้เราสามารถทำแบบนั้นได้ครับ โดยทำแบบนี้
ทำการสร้างไฟล์ : whoami-pod-003.yml
1 | # whoami-pod-003.yml |
จากนั้นสั่งคำสั่งด้านล่างและเปิด Browser และใส่ url เดิมลงไป
1 | # สั่งเพื่อลบ pod ตัวเก่าทิ้งไป |
จากภาพจะเห็นว่า Environment ถูก Set แค่ค่าที่ต้องการจริงๆคือ OWNER (อันนี้ประกาศแบบธรรมดา) กับ CONFIG_DATABASE_FOR_CONNECTION (อันนี้ประกาศแบบใหม่)
อธิบายไฟล์ whoami-pod-003.yml
จากไฟล์เราจะเห็นตัวอย่างมีการประกาศ evironment แบบใหม่คือ
1 | - name: "CONFIG_DATABASE_FOR_CONNECTION" |
valueFrom
ตรงนี้เป็นการบอกว่าค่า Value นั้นให้ไปเอามาจากไหนซึ่งตรงนี้ประกาศว่า configMapKeyRef ซึ่งแปลว่าเอามาจาก configMap ส่วนด้านในส่วน name , key นั้นเป็นการบอกว่า ConfigMap ชื่ออะไร และ key ที่จะให้เอาค่าคืออะไร จากตัวอย่างก็คือไปเอาค่าจาก ConfigMap ชื่อ basic-configmap และ key ชื่อ CONFIG_DATABASE
เอา ConfigMap ไป Mount volume เป็นไฟล์
ในตอนต้นเรารู้แล้วว่า Applicaiton นิยม Config ด้วยไฟล์ แต่ปัญหาเมื่อเอามาใช้กับ k8s คือมันต้องทำการ Mount volume ซึ่งก็จะมีปัญหาเรื่องอ่านเขียนได้จากกี่ Node เวลาแก้ไข Config ต้องไปแก้ที่ Volume ตรงไหน เพื่อแก้ปัญหานั้น k8s จึงทำให้เราสามารถ Mount ตัว ConfigMap ไปเป็น Volume ได้ โดยตัวอย่างนี้ผมจะสร้าง ConfigMap ที่มีค่าเป็นไฟล์ HTML และ Mount volume ไปใน nginx ซึ่งเมื่อเราเรียกผ่าน Browser จะต้องแสดงผลแบบไฟล์ HTML ของเรา
สร้างไฟล์ nginx-configmap.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
จากไฟล์ที่เราประกาศจะเห็นว่าเราใช้เครื่อง “|” ซึ่งเครื่องหมายนี้เป็นการบอกว่าจะค่าที่จะ config นั้นมีหลายบรรทัด โดยในไฟล์นี้เราสร้าง configMap ที่มี 2 key คือ indexFile , wasineeFile
สร้างไฟล์ nginx-pod.yml จากนั้น apply ไฟล์
1 | apiVersion: v1 |
จากนั้นเราเปิด Browser แล้วเข้า URL :
- http://<ip ของเครื่อง run k8s>:32030/index.html (ของผมเป็น http://192.168.156.101:32030/index.html)
- http://<ip ของเครื่อง run k8s>:32030/wasinee.html (ของผมเป็น http://192.168.156.101:32030/wasinee.html)
ซึ่งจะเห็นว่า nginx นั้นแสดงผลไฟล์ index.html เหมือนกับค่าใน configMap key : indexFile และ wasinee.html นั้นแสดงผลตรงกับค่าใน configMap key : wasineeFile
อธิบายไฟล์ nginx-pod.yml
ไฟล์นี้จะคล้ายๆไฟล์ nginx-use-pvc.yml แต่ต่างกันตรงการประกาศ volume
1 | volumes: |
โดยอันนี้เราจะเปลี่ยนจาก persistentVolumeClaim มาเป็น configMap แทน
name
ตรงนี้เป็นการบอกว่าเราจะใช้ configMap ชื่ออะไรในการ Mount volume
items
ตรงนี้เป็นการบอกว่าจะเอา key ไหนไปเป็นไฟล์อะไรบ้างและเอาไปเป็นไฟล์วางไว้ในที่ไหน โดยจากตัวอย่าง เราจะเอา key: indexFile ไปเป็นไฟล์ index.html และ key : wasineeFile ไปเป็นไฟล์ wasinee.html
Secret คืออะไร
ถ้ามองแบบง่ายๆมันก็คือ ConfigMap นั่นแหละครับ แต่เป็น ConfigMap ที่มีการปกป้องไม่ให้สามารถอ่านออกได้แบบตรงๆ (ระดับง่ายสุดคือ base6
4) Secret เหมาะที่จะใช้กับอะไรที่ต้องการเป็นความลับ เช่น password , token , private key เป็นต้น (สามารถอ่านนิยามที่ถูกต้องได้ที่ : Link)
ลองสร้าง Secret
ทำการสร้างไฟล์ basic-secret.yml
1 | apiVersion: v1 |
จากนั้นสั่ง apply และทำการ get และ describe ดู secret
จากภาพจะเห็นว่ามันแสดงผลคล้ายๆกับ configMap เลยคือมี key ให้รู้ว่า secret นี้มี key อะไรบ้าง เพียงแต่เราไม่สามารถเห็นค่า value : secret ได้เหมือนกับ configMap ก็เท่านั้น
อธิบายไฟล์ basic-secret.yml
ในส่วนของ apiVersion , kind , metadata ผมขอไม่พูดนะครับเพราะเหมือนกับ pod , deployment , configMap จะพูดตรง type ลงไป
type
ตรงนี้เป็นการบอกว่า Secret นี้เป็น type อะไร โดย Opaque เป็น type basic ของ secret ตัว type มีอีกมากมายสามารถดูได้ที่ https://kubernetes.io/docs/concepts/configuration/secret/#secret-types
data
ส่วนนี้เป็นการประกาศ key กับ value โดย value จะต้องเป็นค่าที่ถูก Base64 ไว้ครับ
เอา Secret ไปเป็น Environment
ในเมื่อ configMap สามารถเอาไปผูกเป็น Environment ได้ secret ก็น่าจะต้องเอาไปใช้เป็น Environment ได้
** ทำการลบ whoami-pod และ whoami-service ทิ้งก่อนนะครับ
สร้างไฟล์ whoami-pod-004.yml
1 | apiVersion: v1 |
จากนั้นทำการ apply file และเปิด Browser แล้วเปิด URL : http://<ip ของเครื่องที่ run k8s>:32020/api?env=true (ของผมเป็น http://192.168.156.101:32020/api?env=true)
จากภาพจะเห็นว่าค่า username , password นั้นเอามาจาก secret: basic-secret
อธิบายไฟล์ : whoami-pod-004.yml
จากไฟล์จะเห็นว่าส่วนที่แตกต่างไปจากเดิมคือ envFrom
envFrom
ตรงส่วนนี้คือบอกว่าจะเอา env มาจากไหน โดย secretRef คือบอกว่าให้เอาจาก secretRef ซึ่งในตัวอย่างคือ secret ชื่อ basic-secret
1 | envFrom: |
อยาก Set ค่าแค่บาง Environment จาก Secret ล่ะ
หัวข้อนี้เหมือนกับ configMap เลยคืออยาก set : environment แค่บางค่าจาก Secret ล่ะทำยังไง
** ทำการลบ whoami-pod และ whoami-service ทิ้งก่อนนะครับ
สร้างไฟล์ : whoami-pod-005.yml
1 | apiVersion: v1 |
จากนั้นทำการ apply file และเปิด Browser แล้วเปิด URL : http://<ip ของเครื่องที่ run k8s>:32020/api?env=true (ของผมเป็น http://192.168.156.101:32020/api?env=true)
จากภาพจะเห็นว่าค่า Environment : CONFIG_DATABASE_PASSWORD มาจาก basic-secret ที่ key : password
อธิบายไฟล์ : whoami-pod-005.yml
จากตัวอย่างจะเห็นว่าที่แตกต่างจาก configMap คือ valueFrom ที่กำหนดเป็น secretKeyRef
secretKeyRef
1 | - name: "CONFIG_DATABASE_PASSWORD" |
จากตัวอย่างจะเห็นว่าเราบอกว่าเราจะเอาค่าจาก secret ชื่อ basic-secret ที่ key : password ไปเป็น environment ชื่อ CONFIG_DATABASE_PASSWORD
เอา Secret ไป Mount volume เป็นไฟล์
Secret นั้นแทบจะเหมือนกับ ConfigMap ซึ่งตัว ConfigMap สามารถ Mount volume ได้ ดังนั้น Secret ก็น่าจะต้อง Mount volume ได้เช่นกัน
** ทำการลบ nginx-pod และ nginx-service ทิ้งก่อนนะครับ
สร้างไฟล์ : nginx-use-secret.yml
1 | apiVersion: v1 |
สั่ง apply ไฟล์ จากนั้นเราเปิด Browser แล้วเข้า URL : http://<ip ของเครื่อง run k8s>:32030/index.html (ของผมเป็น http://192.168.156.101:32030/index.html)
ซึ่งจากภาพจะเห็นว่าจะได้คำว่า wasinee โผล่ขึ้นมาที่หน้าจอ ซึ่งตรงกับค่า basic-secret ที่ key : username
อธิบายไฟล์ : nginx-use-secret.yml
จากไฟล์จะเห็นส่วนที่แตกต่างจาก configMap คือตรงประกาศ volume นั้นประกาศด้วย secret
secret
1 | volumes: |
จากตัวอย่างจะเห็นว่าเราประกาศบอกว่า volume นี้เอามาจาก secret โดยบอกว่าเอามาจาก secretName ชื่อ basic-secret และเอา key username ไปเป็นไฟล์ index.html ดังนั้นค่า wasinee ที่อยู่ที่ key : username เลยไปกลายเป็นไฟล์ index.html อย่างที่เราทดลอง
สรุป
สำหรับตอนนี้เราได้รู้ว่า ConfigMap กับ Secret คืออะไร ได้รู้วิธีการประกาศ การนำไปใช้เป็น environment และนำไป mount volume เป็นไฟล์ สำหรับตอนต่อไปเราจะไปดูเกี่ยวกับ ingress กันครับ