จากบทความเรื่อง
Write a Kubernetes-ready service from zero step-by-step
ทำการสรุป workflow หรือขั้นตอนของการพัฒนาระบบ REST API ด้วยภาษา Go
เริ่มตั้งแต่การพัฒนา API แบบง่าย ๆ
จากนั้นทำการเพิ่มความสามารถที่จำเป็นต้องมีทั้ง logging, health check และ graceful shutdown
รวมไปถึงการ deploy ระบบงาน
ซึ่งในตัวอย่างจะทำการสร้าง Docker Image
และทำการ deploy ด้วย Kubernetes
จึงทำการแปลและสรุปในแบบที่เข้าใจไว้นิดหน่อย
มาเริ่มกันเลย
ขั้นตอนที่ 1 สร้างระบบ API แบบง่าย ๆ ด้วย Hello World
อย่าลืมทำการทดสอบว่า ทำงานได้ตามที่ต้องการด้วย
มี code ดังนี้
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="1.go"]
ขั้นตอนที่ 2 อย่าลืมการเขียน logging ของระบบ
ทำตั้งแต่เริ่มจะได้งาม ๆ
จะได้รู้ว่าควรหรือไม่ควรเขียนอะไร !!
มี library หรือ framework ให้ใช้เพียบเช่น log,
glog และ
logrus เป็นต้น
ตัวอย่างการเพิ่ม log ใน API แบบง่าย ๆ คือ
- การ start service
- service start เรียบร้อย
- service เกิด error ขึ้นมา
Code น่าจะดูดีขึ้นนะ
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="2.go"]
ขั้นตอนที่ 3 ทำการเพิ่ม router ของ API เข้าไป
ในระบบ API นั้นจะมี endpoint หรือของการทำงานจำนวนมาก
ซึ่งจะกำหนดไว้ในส่วนที่เรียกว่า
router
ถ้ายังทำใน package main หรือในไฟล์เดียว มันจะเยอะเกินไป
ทำให้ดูและและจัดการยาก
ดังนั้นแยกออกมาดีกว่า
ส่วนการพัฒนา router ของ API
ขึ้นอยู่ที่ความชอบว่าจะใช้ library หรือ framework อะไร เช่น
gorilla/mux เป็นต้น
หรือจะเขียนเองเด้วย package net/http ก็ได้ เอาที่สบายใจ
ในการเขียน code นั้นส่วนการจัดการ router ไม่น่าจะอยู่ใน package main นะ !!
ตรงนี้คือการแบ่งหน้าที่รับผิดชอบไปในแต่ละ package
ซึ่งเป็นแนวปฏิบัติที่ดี
ข้อดีคือแก้ไขและดูแลรักษาได้ง่าย
ใคร ๆ เขาก็ทำกันแบบนี้นะ ใช่หรือเปล่า ?
ดังนั้นในระบบของเราจะมี 2 package คือ
- package main สำหรับเริ่ม
- package handlers สำหรับจัดการเรื่องของ router
เริ่มด้วยการสร้างไฟล์ handlers.go สำหรับจัดการ router
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="3.go"]
ต่อมาสร้างไฟล์ home.go สำหรับทำงานในส่วนของ endpoint ชื่อว่า /home
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="4.go"]
จากนั้นทำการแก้ไข main.go เพื่อให้ไปใช้ router ที่สร้างขึ้นมา
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="5.go"]
ก่อนใช้งานก็ต้องติดตั้ง github.com/gorilla/mux ก่อนผ่าน go get !!
ขั้นตอนที่ 4 ว่าด้วยเรื่องของการจัดการ dependency หรือ library ต่าง ๆ
สำหรับระบบใหญ่ และ การทำงานเป็นทีม
สิ่งที่ควรมีคือ เครื่องมือในการจัดการ dependency หรือ library ต่าง ๆ ที่ใช้งาน
ซึ่งใน go นั้นมีให้ใช้เยอะมาก
ทั้งการเขียน shell/bat script กับการใช้ go get
ทั้งการใช้ตัวจัดการ dependency เช่น
dep และ
glide เป็นต้น
โดยในบทความจะใช้ dep ซึ่งติดตั้งไม่ยาก
สามารถใช้งานได้ง่าย ๆ ดังนี้
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="6.txt"]
เพียงเท่านี้ก็มีตัวจัดการ dependency แล้วนะ ง่ายมาก ๆ
ขั้นตอนที่ 5 อย่าลืมชุดการทดสอบ API
เพื่อความสบายใจ สิ่งที่ต้องทำคือ สร้างชุดการทดสอบของ API แรกขึ้นมา
การเริ่มต้นที่ดี มีชัยไปกว่าครึ่งนะครับ
มาเขียนชุดการทดสอบ API กัน
ข้อดีของ go คือมี package ชื่อว่า
httptest มาให้ใช้แล้วนะสิ
มาเขียนกันเถอะ
เริ่มด้วย test case ง่าย ๆ คือ success ไงละ
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="7.go"]
ขั้นตอนที่ 6 จัดการเรื่องของ configuration ของระบบ
ซึ่งจาก
The twelve-factor app นั้น
แนะนำให้ทำการแยก configuration ออกจาก code หรือระบบงานด้วย
นั่นคือให้ใส่ configuration ไว้ในแต่ละ environment แทน
จะเห็นได้ว่าใน code ตัวอย่าง
ทำการ hard code Port ไว้
ดังนั้นเราสามารถทำการเปลี่ยน port ของ API ไปไว้ใน environment variable
จากนั้นใน code ก็เปลี่ยนไปดึงจาก environment variable แทน
ทำให้ง่ายต่อการเปลี่ยนแปลงอีกด้วย ดังนี้
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="8.go"]
ขั้นตอนที่ 7 จัดการเรื่องของ Health check และความพร้อมของ API
เริ่มเข้าสู่เรื่องของ operation ต่าง ๆ ของการ deploy ระบบงาน
ในส่วนนี้ทำให้รู้ว่า API ยังมีชีวิตดีอยู่หรือไม่
ถ้าไม่ จะได้ทำการ restart service ใหม่ขึ้นมา
รวมทั้งยังตรวจสอบความพร้อมต่าง ๆ ของ API
เช่นถ้ามีการใช้ database แล้ว ถ้า API/service ไม่สามารถติดต่อ database ได้
ก็ให้ทำการนำ service นี้ออกไป หรือ ไม่ให้เข้าใช้งานเป็นต้น
ตัวอย่างของ health check ของ API
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="9.go"]
ขั้นตอนที่ 8 ว่าด้วยเรื่องของ Graceful shutdown
เมื่อต้องการที่จะลบหรือหยุดการทำงานของ API แล้ว
สิ่งที่ต้องทำคือ อย่าไปหยุดหรือขัดการทำงานของงานที่ยังทำไม่เสร็จ
ดังนั้นต้องรอจนไปกว่างานทั้งหมดจะทำงานเสร็จ
โดยที่ package http.Server ในภาษา go ตั้งแต่ version 1.8 ขึ้นมาสนับสนุน
แต่วิธีการเขียนจะยากนิดหน่อย
เพราะว่านำ go routine/channel มาใช้ด้วย
สามารถเขียนได้ดังนี้
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="10.go"]
มาถึงตรงนี้จะเห็นได้ว่า
ในการพัฒนาระบบ API นั้นจำเป็นต้องมีสิ่งต่าง ๆ มากกว่า feature นะครับ
ซึ่งทีมพัฒนาต้องให้ความสำคัญด้วยมาก ๆ
อย่าไปทำในช่วงท้าย หรือ ก่อนทำการ deploy
ให้คิด วางแผน และ ลงมือทำตั้งแต่เนิ่น ๆ
จะได้รู้และเข้าใจปัญหา เพื่อแก้ไขกันต่อไป
เข้าสู่ขั้นตอนการ build, ship และ run หรือการ deploy
โดยขั้นตอนเหล่านี้มักจะเรียกว่า Continuous Integration และ Continuous Delivery/Deployment
มาดูกันว่าเป็นอย่างไรบ้าง ?
ซึ่งในบทความจะใช้ Docker และ Kubernetes
มาเริ่มกันเลย
ขั้นตอนที่ 9 ทำการสร้าง Dockerfile เพื่อใช้สำหรับการสร้าง image สำหรับ deploy ต่อไป
เมื่อทุกอย่างพร้อมแล้ว
สิ่งที่ต้องกำหนดคือ กระบวนการ build -> test -> run ที่เป็นมาตรฐาน
เพื่อให้ทุก ๆ คนในทีมทำงานในรูปแบบเดียวกัน
อีกทั้งยังได้ artifact หรือ software package เอาไว้ deploy ต่อไป
ในส่วนนี้มีวิธีการมากมาย
ทั้ง shell/bat script
ทั้ง Makefile
ทั้ง manual process
แต่ในปัจจุบันสิ่งที่ได้รับความนิยมคือ Containerization
เครื่องมือที่ใช้คือ Docker
ดังนั้นเรามาทำการสร้าง Dockerfile เพื่อใช้สร้าง Docker Image กัน
เพื่อใช้ในการ deploy ต่อไป
สิ่งที่ต้องการคือ
- สร้าง Dockerfile
- ทำการ compile -> test -> build software package
- ทำการสร้าง image ไว้สำหรับการ deploy
ซึ่งเราสามารถใช้
Docker multi-stage build ได้
ยกตัวอย่างเช่น
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="Dockerfile"]
จะเห็นได้ว่า กระบวนการต่าง ๆ ทั้ง compile, test และ สร้าง software package อยู่ในนี้
ที่สำคัญ version ต่าง ๆ ของ software ถูกกำหนดไว้ชัดเจนอีกด้วย
ดังนั้นปัญหาน่าจะลดไปได้มาก
การใช้งานก็ง่ายมาก ๆ ดังนี้
[code]
$docker build -t api:1.0 .
$docker run --rm -p 8080:8080 api:1.0
[/code]
ตอนนี้เราได้ Docker Image ที่พร้อมเอาไป deploy แล้วนะ
ทั้งใช้ Docker (ในตัวอย่าง run ไปแล้ว)
ทั้งใช้ Docker Swarm
ทั้งใช้ Kubernetes
เอาที่สบายใจนะครับ
ขั้นตอนที่ 10 ทำการ deploy ระบบ API ด้วย Kubernetes
ในการ deploy ด้วย Kubernetes ต้องจัดเต็ม
ทั้ง service
ทั้ง deployment
ทั้ง ingress
ซึ่งสามารถทำการ configuration ได้ดังนี้
ซึ่งสามารถแยกไฟล์ หรือ รวมไฟล์ได้ประมาณนี้
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="tmp.yaml"]
เมื่อทุกอย่างพร้อม ทำการ deploy ด้วย Kubernetes
ในตัวอย่างจะใช้ minikube เพื่อให้ run แบบ local/stanalone ได้
และทดสอบซะ
[gist id="5d8a524111c8a6f453a3cbffb1190d07" file="11.txt"]
เพียงเท่านี้เราก็ได้ระบบ API แบบง่าย ๆ
ที่พัฒนาด้วยภาษา Go มีทั้ง logging, health check และ graceful shutdown
ไปจนถึงการสร้าง Docker Image และ deploy ด้วย Kubernetes อีกด้วย
น่าจะทำให้เห็น workflow หรือขั้นตอนการพัฒนาที่ดีกว่าเดิม
ขอให้สนุกกับการ coding ครับ
ปล. สิ่งที่ไม่ได้อธิบายคือ เรื่องของ versioning และ Makefile นะครับ