พัฒนาแอพบน Kubernetes ให้เป็นเรื่องง่ายด้วย Skaffold
เกือบ 4 ปีที่เหล่าออเจ้าได้รู้จักหนทางแห่งการ deploy แอพพลิเคชันที่เลิศ scale ระบบได้ดี และจัดการแอพพลิเคชันได้ชิค ๆ คูล ๆ กับเครื่องมือที่ชื่อว่า Kubernetes ที่ดังกระฉ่อนไปทั่วทั้งพระนคร
ทว่า deployment โดยทั่วไปยังฝากชะตากรรมนี้ไว้กับ devops ทีม โปรแกรมเมอร์นั้นฤางานกรรมกรมีหน้าที่โค้ดก็โค้ดไปซิ จะกระสันไปจุ้นส่วนอื่นทำไม
โลกเปลี่ยนคนเปลี่ยน เมื่อสภาพแวดล้อมในการพัฒนาเช่นระบบปฏิบัติการไม่ตรงกับการทำงานบน production บางครั้งปัญหาจึงเกิด โปรแกรมเมอร์จึงต้องขายวิญญาณด้วยการสร้าง containerized app ผ่าน Docker ส่วนงาน deploy นั้นไซร์ให้ทีมอาวุโสอย่าง devops ทำต่อไปเถอะ
ถึงกระนั้นปัญหายังคงราวี แม้ตอนนี้โปรแกรมเมอร์จะควบคุมและจัดการ dependencies ในการพัฒนาให้ใกล้เคียงกับการใช้งานจริงได้แล้วก็ตาม แต่ขั้นตอนของการ deploy นั้นก็ไม่การันตีว่าจะทำให้แอพพลิเคชันของเราไม่นิพพานก่อนวัยอันควร โปรแกรมเมอร์ที่น่าสงสารจึงต้องเรียนรู้เพื่อใช้งาน Kubernetes จะได้ทดสอบและตรวจสอบการทำงานให้ถูกต้องก่อนการส่งมอบงาน
กระบวนการพัฒนาซอฟต์แวร์ด้วย Kubernetes
โดยทั่วไปกระบวนการพัฒนาจึงเป็นเช่นนี้ 1
- จัดหาคลัสเตอร์ของ Kubernetes ซะก่อนไม่ว่าจะเป็น GKE AKS หรือเครื่องมืออย่าง kops
- Build Docker Image และทำการอัพโหลดไปยัง registry เพื่อใช้งานบนคลัสเตอร์
- สร้าง Kubernetes manifest เพื่อใช้งานตามเอกสารของ Kubernetes
- Deploy แอพพลิเคชันผ่าน kubectl CLI หรือ Kubernetes Dashboard
- ทำซ้ำข้อ 2 - 4 จนกว่ากาพัฒนาฟีเจอร์หรือการแก้ข้อผิดพลาดจะเสร็จสิ้น
- โยนโครมลง CI เพื่อทำ Unit testing Integration testing และ deploy ลงสภาพแวดล้อมแบบ test หรือ staging
แค่อ่านก็หาวแล้วใช่ไหม โดยปกติขั้นตอนที่ 2 - 5 มักเป็นกระบวนการทำมือผ่านเครื่องมือต่าง ๆ และบางอย่างก็เป็นเรื่องที่ต้องตบตีกันเอาเองว่าจะใช้ท่าไหน เช่น บางคนกำหนดเลข tag ด้วยการนับเพิ่มเรื่อยๆ จาก 1 ไปถึงไหนก็ไม่รู้ แต่ถ้าวันนึง deploy เยอะมากนับเลขคงไม่ไหว เอา tag เป็นเลข commit ของ GIT แล้วกัน เป็นต้น
รู้จัก Skaffold เครื่องมือที่จะทำให้การพัฒนาเป็นเรื่องง่าย
ทั้งหมดทั้งมวลจะเห็นว่าขั้นตอนที่ 2 - 5 นั้นยุ่งยากและเป็นส่วนที่สามารถ automate ได้ จึงเกิดเครื่องมือสนอง need ต่าง ๆ มากมาย เช่น Draft จาก Microsoft Forge จาก Datawire และ Flux จาก Weavework
และล่าสุดกับ Skaffold เครื่องมือสุดเจ๋งที่จะช่วยเหล่าออเจ้าลดความยุ่งยากในการพัฒนาแอพพลิเคชันและ deploy ด้วย Kubernetes
ไม่ต้องพูดพร่ำทำเพลงเยอะ ลอง build push และ deploy แอพพลิเคชัน Node.js ด้วย Skaffold ดูซิว่ามันเจ๋งแค่ไหนแล้วค่อยกลับมาสรุปกันอีกครั้ง
build/push/deploy แอพพลิเคชัน Node.js ด้วย Skaffold
ก่อนที่จะทดลองใช้งาน Skaffold ขอให้มั่นใจก่อนว่าเพื่อน ๆ ได้ทำการติดตั้ง Docker Minikube และ kubectl เป็นที่เรียบร้อยแล้ว หลังจากนั้นจึงทำการติดตั้ง Skaffold ในลำดับถัดไป สำหรับระบบปฏิบัติการ MacOS ดำเนินการติดตั้งผ่านคำสั่งนี้
1curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-darwin-amd64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin
เมื่อทุกอย่างพร้อม เราก็พร้อมไปต่อกับการสร้างเซิฟเวอร์อย่างง่าย ๆ ด้วย express.js ผ่าน package.json ดังนี้
1{2 "name": "skaffold",3 "version": "1.0.0",4 "description": "",5 "main": "index.js",6 "scripts": {7 "start": "node index.js"8 },9 "author": "",10 "license": "ISC",11 "dependencies": {12 "express": "^4.16.3"13 }14}
และนี่คือโค้ดหลักของโปรแกรมเราใต้ index.js
1const express = require('express')2const app = express()34app.get('/', function(req, res) {5 res.send('Babel Coder!')6})78app.listen(3000, err => {9 if (err) throw err1011 console.log('server is listening');12})
แอพพลิเคชันพร้อม! ต่อไปก็เตรียมความพร้อมสำหรับการสร้าง Docker Image ไว้ใช้กับคลัสเตอร์ผ่านการนิยามด้วย Dockerfile
1FROM node:8.10.0-alpine23WORKDIR /usr/src/app45COPY package.json .6COPY package-lock.json .7RUN npm install89COPY . .1011EXPOSE 30001213CMD npm start
โดยปกติเมื่อถึงขั้นตอนนี้เราต้องทำการ build และแปะ tag เพื่อสร้าง Docker Image สำหรับนำไปใช้ต่อ แต่ตอนนี้เราฉลาดขึ้นแล้วผลักภาระไปให้ Skaffold ทำเองเถอะแม่หญิง
ถัดไปจึงสร้าง deployment และ service ผ่านไฟล์ k8s.yml ดังนี้ 2
1apiVersion: extensions/v1beta12kind: Deployment3metadata:4 name: node-app5spec:6 replicas: 17 template:8 metadata:9 labels:10 app: node-app11 spec:12 containers:13 - name: node-app14 image: IMAGE_NAME15 ports:16 - containerPort: 300017---18apiVersion: v119kind: Service20metadata:21 name: node-app22 labels:23 app: node-app24spec:25 selector:26 app: node-app27 ports:28 - port: 300029 protocol: TCP30 nodePort: 3000331 type: LoadBalancer
โปรดสังเกตว่าเราจะไม่ระบุ Docker image ลงไปในส่วนของ containers นั่นเพราะถ้าเราทำมือเองเมื่อ tag เปลี่ยนเราก็ต้องเปลี่ยนส่วนนี้เองตลอด แต่เราจะระบุเป็น IMAGE_NAME แทนเพื่อให้ Skaffold จัดการสร้าง image พร้อม tag ใหม่ให้กับเราทุกครั้งที่โค้ดเราเปลี่ยน และทำการแทนที่ IMAGE_NAME ด้วยชื่อ image นั้น
คำถาม แล้ว Skaffold รู้ได้อย่างไรว่า IMAGE_NAME ควรมีชื่อเป็นอะไร? เราจึงต้องสร้างไฟล์ชื่อ skaffold.yaml เพื่อนิยามการทำงาน ดังนี้
1apiVersion: skaffold/v1alpha12kind: Config3build:4 artifacts:5 - imageName: node-app6 workspace: .7 local: {}8deploy:9 kubectl:10 manifests:11 - paths:12 - k8s.yml13 parameters:14 IMAGE_NAME: node-app
เมื่อโค้ดของเราเกิดการเปลี่ยนแปลง Skaffold จะทำการ build image ใหม่ทุกครั้งด้วยชื่อที่เราระบุใน IMAGE_NAME พร้อมแปะ tag ให้กับเราอัตโนมัติ ส่วนโปรแกรมเมอร์นั้นหรือ จิบกาแฟไปซิ~
เอาหละตอนนี้ก็ถึงเวลาทดลองกันแล้ว เมื่อเป็นการพัฒนาบนเครื่องจงอย่าลืมที่จะปลุกชีพ Minikube ขึ้นมาก่อนด้วยคำสั่ง minikube start
จากนั้นจึงสั่ง Skaffold ให้ทำการ build/push/deploy ให้กับเราด้วยคำสั่ง skaffold dev
1Starting build...2Found minikube or Docker for Desktop context, using local docker daemon.3Sending build context to Docker daemon 1.944MB4Step 1/8 : FROM node:8.10.0-alpine5 ---> adc4b0f5bc536Step 2/8 : WORKDIR /usr/src/app7 ---> Using cache8 ---> 484a011055f19Step 3/8 : COPY package.json .10 ---> 48c848a33ca811Step 4/8 : COPY package-lock.json .12 ---> b467f6dff7ee13Step 5/8 : RUN npm install14 ---> Running in 9da273042e8f15added 49 packages in 1.165s16 ---> b6e8c2d170b417Step 6/8 : COPY . .18 ---> 2d977d626ad819Step 7/8 : EXPOSE 300020 ---> Running in f32b155a225e21 ---> 44b426f6672322Step 8/8 : CMD npm start23 ---> Running in 521fc2ea13ca24 ---> 68e3745c933825Successfully built 68e3745c933826Successfully tagged 05cd3c1f9adb2e24f0660a3eb51071ea:latest27Successfully tagged node-app:68e3745c933892673713541009428c3f1e4e7437f6f2c33ddd7aa5f706e2bfc728Build complete.29Starting deploy...30Deploying k8s.yml...31Deploy complete.
จะสังเกตได้ว่า Skaffold ทำการแปะ tag ให้กับเราอัตโนมัติด้วยชื่อจาก IMAGE_NAME และค่า hash ออกคำสั่งล่างนี้เพื่อดูผลลัพธ์เป็นการแสดงผล Babel Coder! ออกหน้าจอ
minikube service node-app
ยังไม่จบแค่นั้นครับ Skaffold ยังตรวจจับการเปลี่ยนแปลงโค้ดได้ด้วย เมื่อไหร่ที่โค้ดของเราเปลี่ยนมันจะทำการ build/push/deploy ให้กับเราอย่างอัตโนมัติ ลองเปลี่ยนโค้ดของ index.js จาก
1app.get('/', function (req, res) {2 res.send('Babel Coder!')3})
เป็น
1app.get('/', function (req, res) {2 res.send('Babel Coder Rocks!')3})
แล้วชะโงกหน้าดูที่ terminal ก็จะพบความจริงว่า...
1Starting build...2Found minikube or Docker for Desktop context, using local docker daemon.3Sending build context to Docker daemon 1.944MB4Step 1/8 : FROM node:8.10.0-alpine5 ---> adc4b0f5bc536Step 2/8 : WORKDIR /usr/src/app7 ---> Using cache8 ---> 484a011055f19Step 3/8 : COPY package.json .10 ---> Using cache11 ---> 48c848a33ca812Step 4/8 : COPY package-lock.json .13 ---> Using cache14 ---> b467f6dff7ee15Step 5/8 : RUN npm install16 ---> Using cache17 ---> b6e8c2d170b418Step 6/8 : COPY . .19 ---> 41d5b84d7feb20Step 7/8 : EXPOSE 300021 ---> Running in 12da84409ecb22 ---> 8831c075517323Step 8/8 : CMD npm start24 ---> Running in ebe7b8e815d025 ---> b4a1e92c24b726Successfully built b4a1e92c24b727Successfully tagged 8d090121e01a29734b5b997f9bc114fb:latest28Successfully tagged node-app:b4a1e92c24b76f7507713806e02496e27e8d67236130dbf72e22246e569585ca29Build complete.30Starting deploy...31Deploying k8s.yml...32Deploy complete.
เมื่อ Skaffold ตรวจพบการเปลี่ยนแปลงจึงทำการ build/push/deploy ใหม่อีกครั้ง หากออกคำสั่ง minikube service node-app
เราก็จะพบผลลัพธ์ที่เปลี่ยนไป
Skaffold ดีอย่างไร
หลังจากลองเล่น Skaffold กันไปแล้ว ถึงเวลาแล้วหละที่จะสรุปว่า Skaffold นั้นควรค่าแก่การขึ้นหิ้งอย่างไร
- Skaffold นั้นตรวจจับการเปลี่ยนแปลงแล้วทำการ build/push/deploy ให้ใหม่ ไม่กวนเวลาจิบกาแฟยามเที่ยงและงีบหลับในเวลางานของเรา
- จัดการ image tag ให้กับเราผ่าน sha256 จากโค้ดของเรา แต่ถ้าเป็นบน CI/CD ก็จะใช้ git commit แทน
Skaffold นั้นให้สิทธิ์ในการเลือกเครื่องมือที่เหมาะสมสำหรับเรา เช่น deploy บน Minikube บน development และใช้ GKE กับ Helm บน production
สรุป
Skaffold นั้นเป็นอีกหนึ่งเครื่องมือที่ช่วยให้งานพัฒนาและการส่งมอบเป็นเรื่องง่าย จากงานมือทำซ้ำซากให้เป็นงานหน่อมแน้มทำอัตโนมัติ หากเพื่อน ๆ คนไหนสนใจสามารถอ่านเพิ่มเติมได้จาก Repo ของ Skaffold ครับ
เอกสารอ้างอิง
Daniel Bryant. (2018) Google Releases “Skaffold”, a Tool That Facilitates Continuous Development with Kubernetes. Retrieved Mar, 23, 2018, https://www.infoq.com/news/2018/03/skaffold-kubernetes
Vic Iglesias. (2018) Introducing Skaffold: Easy and repeatable Kubernetes development. Retrieved Mar, 23, 2018, from https://cloudplatform.googleblog.com/2018/03/introducing-Skaffold-Easy-and-repeatable-Kubernetes-development.html
Gergely Nemeth. (2018) Using Kubernetes for Local Development. Retrieved Mar, 23, 2018, https://nemethgergely.com/using-kubernetes-for-local-development/
สารบัญ
- กระบวนการพัฒนาซอฟต์แวร์ด้วย Kubernetes
- รู้จัก Skaffold เครื่องมือที่จะทำให้การพัฒนาเป็นเรื่องง่าย
- build/push/deploy แอพพลิเคชัน Node.js ด้วย Skaffold
- Skaffold ดีอย่างไร
- สรุป
- เอกสารอ้างอิง