Zero-downtime Deploy ด้วย Blue-Green และ Rolling Update
· 1 min read
หลายทีมย้ายมาใช้ rolling update แล้วยังเจอ error ช่วง deploy อยู่ดี เพราะกลยุทธ์ deploy เป็นแค่ครึ่งเดียวของเรื่อง อีกครึ่งคือแอปต้องพร้อมถูกปิดและถูกเปลี่ยนรุ่นระหว่างที่ยังมี traffic วิ่งอยู่
Rolling update
ทยอยเปลี่ยน pod ทีละชุด ระบบจะมีทั้งรุ่นเก่าและรุ่นใหม่ทำงานพร้อมกันช่วงหนึ่ง ข้อดีคือไม่ต้องใช้ทรัพยากรเพิ่มมาก ข้อเสียคือต้องรองรับการมีสองรุ่นพร้อมกันได้จริง โดยเฉพาะเรื่อง schema ของฐานข้อมูลและรูปแบบข้อความใน queue
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1maxUnavailable: 0 คือค่าที่ควรใช้เมื่อไม่อยากให้ความจุลดลงระหว่าง deploy แลกกับการใช้ทรัพยากรเกินชั่วคราวหนึ่ง pod
Blue-green
ยกสภาพแวดล้อมใหม่ขึ้นมาทั้งชุด ทดสอบให้เรียบร้อย แล้วค่อยสลับ traffic ทีเดียว ข้อดีคือ rollback เร็วมากเพราะแค่สลับกลับ ข้อเสียคือต้องมีทรัพยากรสองเท่าในช่วงสลับ และ connection ที่ค้างอยู่บนฝั่งเก่าต้องมีแผนรองรับ
เงื่อนไขที่ต้องมี ไม่งั้นยังพังอยู่ดี
Readiness probe ที่บอกความจริง — ถ้า probe ตอบ 200 ตั้งแต่ก่อนแอปเชื่อมต่อฐานข้อมูลได้ traffic จะถูกส่งเข้ามาก่อนเวลาอันควร
จัดการ SIGTERM ให้ถูก — ตอนถูกสั่งปิด แอปต้องหยุดรับงานใหม่ แล้วทำงานที่ค้างอยู่ให้จบก่อนออก
process.on('SIGTERM', async () => {
server.close()
await drainInFlightJobs()
process.exit(0)
})Migration ต้องเข้ากันได้ทั้งสองรุ่น — เปลี่ยน schema แบบเพิ่มก่อนเสมอ เช่นเพิ่มคอลัมน์ใหม่ ปล่อยโค้ดที่เขียนทั้งคอลัมน์เก่าและใหม่ แล้วค่อยลบคอลัมน์เก่าใน deploy ถัดไป การลบคอลัมน์พร้อมกับ deploy โค้ดใหม่คือสาเหตุคลาสสิกของ downtime ระหว่าง rolling update
วัดผลว่าไม่มี downtime จริงไหม
อย่าเชื่อว่า deploy สำเร็จเพราะ dashboard เขียวอย่างเดียว ให้ยิง request ต่อเนื่องระหว่าง deploy แล้วนับ error
while true; do
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/healthz
sleep 0.2
doneถ้าเห็น 502 หรือ connection reset แม้เพียงไม่กี่ครั้ง แปลว่ายังมีช่องว่างระหว่างการถอด pod ออกจาก load balancer กับการที่แอปหยุดรับ connection