Basic Kubernetes Part 7 - ทำโจทย์ - Deploy Wordpress บน k8s
WordPress เป็น Application หนึ่งที่ถูกเอามาใช้เพื่อสร้างเป็น Web ซึ่งได้รับความนิยมเป็นอย่างมากเพราะคนสามารถเอาไปดัดแปลงทำได้หลายอย่าง ตั้งแต่ Blog บอกเล่าเรื่องราวของคนทั่วไป ไปจนถึง ทำ Web ขายของออนไลน์ก็ได้ ใครอยากรู้ว่า WordPress คืออะไรแบบละเอียด กดที่ Link แล้วหาอ่านเพิ่มเติมได้เลย
วิเคราะห์โจทย์
คราวนี้ถ้าเราจะ Deploy ตัว WordPress ล่ะเราจะต้องทำอะไรบ้าง อย่างแรกคือเราต้องรู้ก่อนว่าตัว WordPress ต้องการอะไรบ้าง และมี Docker ให้ใช้ไหม
มี Docker ให้ใช้ไหมและต้องใช้อะไรบ้าง
เราสามารถ Search ที่ google ด้วยคำว่า WordPress + Docker ซึ่งเราก็เจอที่ Dockerhub โดยเรามี Docker ของ WordPress ให้ใช้ พร้อมบอกวิธีการ Set: ENVIRONMENT ด้วย
ซึ่งจากการดู ENVIRONMENT แล้ว เราจะพบว่าตัว WordPress เนี่ยต้องการใช้ MySQL ด้วย ซึ่งถ้าเรามี MySQL อื่นให้ใช้ก็ OK แต่เราไม่มีดังนั้นแปลว่าเราต้องสร้าง Database ด้วย
สรุปแล้วเราต้อง Deploy container 2 ตัวคือ
WordPress
MySQL
เริ่มสร้างไฟล์เพื่อ Deploy
ตัวอย่างไฟล์ทั้งหมดสามารถดูได้ที่ Link
สร้างส่วนที่เกี่ยวกับ MySQL
สิ่งที่ต้องสร้างสำหรับส่วน MySQL ที่ต้องมีคือ
- Deployment ที่มีไว้สร้าง Pod
- Service ที่ใช้เป็นตัวเปิดเส้นทางให้สามารถ Request ไปหา Pod ได้
- ConfigMap เนื่องจากเราอยากแยก Config ออกจาก Deployment
- Persistent Volume เนื่องจากตัว MySQL ต้องมีที่เก็บข้อมูล
- Persistent Volume Cliam ต้องสร้างเพื่อให้ Pod สามารถเข้าถึง Volume ที่ต้องการได้
สร้างส่วน PV , PVC
ทำการสร้างไฟล์ mysql-volume.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
โดยไฟล์นี้จะทำการสร้าง pv กับ pvc เพื่อใช้เก็บข้อมูลของ MySQL โดยในการใช้งานจริงเราไม่ควรใช้ Storage ประเภท hostPath นะครับ เพราะมันจะทำให้เวลา Deploy เราจะต้องบังคับให้ Pod อยู่กับ Node ที่มี Volume อยู่เท่านั้น ไม่สามารถกระจายไป Node ต่างๆได้ ในงานจริงควรจะเป็นพวก nfs ครับ
สร้าง ConfigMap
สร้างไฟล์ mysql-configmap.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
เนื่องจากเราต้องการแยก config ออกจาก deployment เราจึงแยกออกมาเป็น ConfigMap โดยค่าที่อยู่ใน configMap คือ ENVIRONMENT ที่เราอยากจะเอาไป set ใน pod โดย Environment ที่เราจะ set คือ MYSQL_ROOT_PASSWORD (อันนี้คือตั้งค่า root password ) , MYSQL_DATABASE (อันนี้คือสร้าง database ชื่ออะไร)
สร้าง Deployment
สร้างไฟล์ mysql-deployment.yml จากนั้นสั่ง apply
1 | apiVersion: apps/v1 |
ไฟล์นี้ทำการสร้าง Deployment โดยใช้ environment จาก oonfigMap : mysql-configmap และทำการ mount volume ไปที่ /var/lib/mysql โดยใช้ volume จาก mysql-pvc
สร้าง Service
ทำการสร้างไฟล์ : mysql-service.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
โดยไฟล์นี้ทำการสร้าง Service type NodePort โดยให้เข้าที่ port : 32020 จากนั้นลองตรวจสอบว่าสามารถใช้งาน
จากภาพผมใช้ตัว dbeaver เข้าไปตรวจสอบว่าสามารถใช้งาน MySQL ได้ไหมและมี Database ชื่อ wordpress_db ที่สั่งสร้างไหม ซึ่งปรากฏว่าดังที่สร้าง
สร้างส่วนที่เกี่ยวกับ WordPress
ในส่วนของ WordPress นั้นมีส่วนที่เราต้องสร้างดังต่อไปนี้
- ส่วน Deployment เพื่อทำการสร้าง Pod
- Service ที่ใช้เป็นตัวเปิดเส้นทางให้สามารถ Request ไปหา Pod ได้
- ConfigMap เนื่องจากเราอยากแยก Config ออกจาก Deployment
- Ingress เนื่องจากเราต้องการใช้งาน WordPress ผ่าน Port 80
ในส่วนของ Volume นั้นเราไม่ได้ใช้เพราะเราจะทำการ Save ข้อมูลลง MySQL ซึ่งเราสร้างไปแล้ว
สร้าง ConfigMap
สร้างไฟล์ wordpress-configmap.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
จากไฟล์เราสร้าง configMap โดยค่า configMap นี้จะเอาไปใช้เป็น Environment โดย Environment ที่เราตั้งค่าไว้จะเกี่ยวกับ Database เพราะ WordPress ต้องใช้ database หากสังเกตจะเห็นว่า WORDPRESS_DB_HOST นั้นเราชี้ไปหา service : mysql-service ที่เราสร้างโดยใช้ชื่อ service (ใครงงกลับไปอ่านตอน service นะครับ)
สร้าง Deployment
สร้างไฟล์ wordpress-deployment.yml จากนั้นสั่ง apply
1 | apiVersion: apps/v1 |
โดยจากไฟล์จะเห็นว่าเราสร้าง wordpress โดยเอา environment จาก configMap : wordpress-configmap และเปิด port 80
สร้าง Service
สร้างไฟล์ wordpress-service.yml จากนั้นสั่ง apply
1 | apiVersion: v1 |
จากไฟล์เราจะทำการสร้าง service แบบ NodePort ที่ port 32030 แล้วชี้ไปที่ pod ที่มี label เป็น app = wordpress-app
ทำการทดลองเปิด Browser แล้วเข้า URL - http://<ip ของเครื่องที่ run>:32030 ของผมเป็น http://192.168.156.101:32030 ซึ่งเมื่อเปิดแล้วจะได้เป็นดังภาพ
จะเห็นว่าเราสามารถเปิด Wordpress ได้ (ไม่ต้องตกใจครับ มันคือหน้า install เนื่องจากเราเข้ามาครั้งแรก)
ส่วน Ingress
สร้างไฟล์ wordpress-ingress.yml
1 | apiVersion: networking.k8s.io/v1 |
สุดท้ายเป็นการสร้าง ingress ให้สามารถเข้าผ่าน port 80 ได้ โดยเราตั้งกฏว่าถ้าเข้ามาด้วย domain name : wordpress-application.com จะ route ไปที่ service : wordpress-service
เรามาทดสอบว่า ingress ว่าใช้งานได้ไหมโดยเปิด Browser ไปที่ : http://wordpress-application.com (อย่าลืม set file hosts ก่อนนะครับ)
ซึ่งจากภาพจะเห็นว่าเราสามารถเปิด wordpress ได้
ลองใช้งาน Wordpress เพื่อตรวจสอบ
ลองมาใช้งาน wordpress เพื่อทดสอบว่ามีปัญหาอะไรไหม โดยเราลองทำการ install และใช้งาน
จากนั้นลอง login ด้วย username , password ที่เราใส่ไปตอน install
ซึ่งเมื่อ Login เข้าไปแล้วจะเข้าไปหน้า Manage ดังภาพ
ซึ่งจากการทดลองเล่นนั้นไม่พบว่าติดปัญหาอะไร ซึ่งนั่นก็พอจะการันตีได้แล้วว่าเรา Deploy ตัว WordPress สำเร็จ
แล้วถ้าอยาก Deploy wordpress แบบนี้อีกหลายตัวล่ะ
ถ้าสมมติมีความต้องการ Deploy : wordpress อีกหลายๆตัวล่ะ เช่น บริษัท A , บริษัท B , บริษัท C wordpress ของละบริษัทต้องมี mysql ของตัวเอง domain name ของตัวเอง แล้วเราทำอะไรได้บ้าง
1. Copy File
ง่ายๆเลยก็คือเรา copy ไฟล์ที่เราสร้างทั้งหมดแล้วไปแก้ไฟล์ตามแต่ละบริษัทต้องการ วิธีนี้ก็ง่ายครับเราสามารถทำได้เลย แต่ปัญหาถ้าบริษัทที่ต้องการไม่ใช่ 3 บริษัทแต่เป็น 100 บริษัทล่ะจะเป็นยังไง แค่นึกภาพว่าต้อง copy ไฟล์ทุกไฟล์ที่ว่ามาแล้วไปไล่แก้แต่ละไฟล์ก็เหนื่อยแล้ว
2. ใช้ envsubst
เราจะใช้ envsubst ร่วมกับการใช้ environment เพื่อทำการ Deploy หลายๆ config
โดยเราจะใช้ envsubst กับค่าที่เปลี่ยนแปลงไปในแต่ละบริษัทตัวอย่างเช่น ตัวอย่างเช่น domain name โดยเราจะทำประมาณนี้
ทำการสร้างไฟล์ : wordpress-ingress-envsubst.yaml
1 | apiVersion: networking.k8s.io/v1 |
จากนั้นลองสั่ง
1 | export DOMAIN_NAME=wasinee-application.com |
จากภาพจะเห็นว่าค่าของ DOMAIN_NAME ที่เรา set ไว้นั้นไปแทนที่ค่าที่ $DOMAIN_NAME ในไฟล์ wordpress-ingress-envsubst.yaml โดยหากเราจะใช้วิธีนี้เราต้องทำดังต่อไปนี้
- สร้าง template file
- สร้าง environment file
- สร้าง script เพื่อทำการ deploy
สร้าง Template file
ทำการสร้างไฟล์ whoami-template.yml
1 | apiVersion: v1 |
จากไฟล์จะเห็นว่ามีการใช้ environment 2 ในไฟล์คือ
- OWNER : อันนี้มีไว้ set ใน whoami เพื่อใช้ดูว่าค่าถูก set จริงไหม และไปถูก Pod ไหม
- DOMAIN_NAME : อันนี้มีไว้ set domain name ไว้ใช้ตอน ingress
สร้าง environment file
สร้างไฟล์ company-a.sh และใส่ค่าตามด้านล่าง
1 | export DOMAIN_NAME=company-a.com |
สร้างไฟล์ company-b.sh และใส่ค่าตามด้านล่าง
1 | export DOMAIN_NAME=company-b.com |
ส่วนนี้คือการกำหนด environment ตามที่เราจะไปใช้กับ Template และ script โดยเราจะทำ 2 ไฟล์คือ company-a.sh กับ company-b.sh ซึ่งถ้าโดยไม่ต้องสน file extension มันคือไฟล์ config ดีๆนี่เอง
สร้าง script เพื่อทำการ deploy
สร้างไฟล์ deploy.sh
โดย script นี้ไม่มีอะไรมากคือทำการรับ parameter 1 ตัวเข้ามา ซึ่ง parameter ที่รับเข้ามาคือไฟล์ environment จากนั้นก็จะไปทำการ set environment ด้วยคำสั่ง source จากนั้นจะทำการเช็ค namespace ว่าเคยมีไหม ถ้าไม่มีจะทำการสร้าง (namespace ขอติดไว้ก่อน แต่มองว่า namespace เหมือนเป็นจักรวาลใน marvel ละกัน ถ้าอยู่คนละ namespace ถือว่าอยู่คนละจักรวาล ยุ่งเกี่ยวกันยากถ้าไม่ผ่านช่องทางที่กำหนด) จากนั้นทำการใช้คำสั่ง envsubst เพื่อแทนค่า environment ไปใน template และส่งผลลัพธ์นั้นไปให้คำสั่ง kubectl apply ทำงานต่อ
1 | echo $1 |
ลอง Deploy
ตัวอย่างไฟล์ทั้งหมดเกี่ยวกับการทำ template deploy สามารถดูได้ที่ : Link
เดี๋ยวผมจะทำตัวอย่างการ Deploy โดยใช้คำสั่งด้านล่าง
1 | # deploy โดยใช้ environment config ของ company-a |
จากนั้นลองสั่งด้านล่างเพื่อเช็คว่าสามารถสร้าง pod และ service สำเร็จหรือไม่
1 | kubectl get all --namespace company-a |
ซึ่งจะเห็นว่ามีการสร้าง pod และ service ขึ้นมาทั้ง 2 namespace(จักรวาล) และสังเกตุจะเห็นว่าชื่อ pod และ service เหมือนกัน ซึ่งในกรณีที่เราทำแบบไม่กำหนด namespace มันจะไปอยู่ที่ default ซึ่งถ้ามีชื่อซ้ำกันมันจะทำการ update ดังนั้นถ้าอยากให้ชื่อซ้ำกันได้ก็ต้องแยกไปอยู่คนละ namespace (ลองเทียบในหนัง จักรวาล 616 มี Spider man ได้คนเดียว แต่จักรวาลอื่นก็มี Spider man ได้เหมือนกัน )
คราวนี้เรามาลองเปิด Browser แล้วเข้า URL ดังต่อไปนี้เพื่อเช็คว่า Ingress ทำงานได้ไหมและ Route ไปถูกเครื่องรึเปล่า (อย่าลืม set file hosts)
1 | http://company-a.com/?env=true |
จากภาพจะเห็นว่า Ingress route ได้ถูกดูได้จากค่า OWNER ที่วงแดงไว้ ซึ่งตรงกับการ config ใน environment ของเรา
วิธีนี้ดียังไง
วิธีนี้ดีกว่าวิธีแก้ไฟล์ยังไง อย่างแรกคือคุณไม่ต้องตามไปแก้ไฟล์ yml ทุกไฟล์ คุณต้องทำการแก้แค่ไฟล์ environment config เพียงไฟล์เดียว ถ้าในตัวอย่างที่เราทำหากต้องเพิ่ม company-c เราก็แค่สร้างไฟล์ company-c.sh จากนั้นกำหนดค่าให้ไฟล์ environment config เท่านั้น แถมเวลาอัพเดทเกี่ยวกับการ Pod service ingress ต่างๆนาๆ เราสามารถแก้ที่ชุด template ที่เดียวเลย ไม่ต้องไปไล่แก้ทุกอันที่เคย Deploy (ถ้า Deploy ไปแล้ว 100 เจ้า แล้วจะเพิ่มอะไรสักอย่างแล้วต้องไปแก้ 100 เจ้า สยองขวัญน่าดู)
มีวิธีที่ดีกว่านี้ไหม
คำตอบคือมีครับ หากเราลองคิดดีๆการที่เราทำมันคือการทำงานเกี่ยวกับ Template processor แบบพวก PHP ที่สามารถใส่ตัวแปรไปใน HTML แล้วสั่ง rendering หรือ JSP และ Template engine อีกมากมาย โดยพวก Template engine พวกนี้จะมีลูกเล่นอีกมากมายที่สามารถทำได้ เช่น if else กับ template เช่น ถ้าค่า type เป็น VIP ให้ทำการใช้ template ส่วนนี้ด้วย หากไม่ใช่ให้ใช้ template ที่ไม่มีส่วนนี้ ซึ่งในงานจริงคุณต้องเจอมันแน่ๆ เช่น บริษัท W เป็นลูกค้าระดับ VIP ดังนั้นเขาต้องการการทำงานที่เร็วกว่าปกติ เราจึงต้องเอา REDIS มาทำ CACHE ในการดึงข้อมูล ดังนั้นจะต้องมี Pod ของ REDIS เพิ่มเข้ามา แต่เพิ่มเข้ามาแค่เฉพาะลูกค้าที่เป็น VIP ถ้าที่เราทำอยู่ตอนนี้น่าจะไม่พอในการทำแบบนั้น
แต่โชคดีครับที่ชาวโลกมีคนเห็นปัญหานี้เหมือนกันและได้สร้างสิ่งที่มาช่วยในการทำแบบนี้ซึ่งนั่นก็คือ HELM ซึ่ง HELM เนี่ยทำได้มากกว่าเป็น Template engine มันสามารถทำ version ของการ Deploy ได้ด้วย ประมาณว่าถ้าคุณทำตัว template deploy ใหม่ไปอัพเดทแล้วเกิดปัญหา คุณสามารถสั่งให้ helm เนี่ยกลับไปใช้ตัว deploy ก่อนหน้าที่ไม่มีปัญหาได้เลย
สรุป
สำหรับตอนนี้เราได้ลองทำโจทย์ Deploy Wordpress กันไปแล้ว ซึ่งจะเห็นว่าไม่ได้ยากมากเลย แถมเรายังได้รู้ปัญหาเกี่ยวกับ Deploy และทำให้เรามารู้จักกับ Tool ที่ใช้ตัว Deploy ที่เราจะไปเรียนรู้กันในตอนต่อไปซึ่งนั่นก็คือ HELM