AWS Thai Blog
วิธีการ Scale แอปพลิเคชันด้วย ALB บน EKS (โดยไม่กระทบกับ Traffic)
เพื่อให้รองรับกับความต้องการของผู้ใช้งาน แอปพลิเคชันที่เป็น Dynamic HTTP-based จำเป็นต้องมีการ Scale Kubernetes pods อย่างสม่ำเสมอ สำหรับที่แอปพลิเคชันที่เปิดใช้งานผ่าน Kubernetes ingress AWS Application Load Balancer (ALB) จะช่วยกระจาย Traffic ที่เข้ามาโดยอัตโนมัติไปที่ Replica ใหม่ที่ Scale ขึ้นมา เมื่อแอปพลิเคชัน Scale-down เนื่องจากความต้องการใช้งานแอพพลิเคชันที่ลดลงแล้ว ผู้ใช้งานอาจได้รับผลกระทบสั้น ๆ จากการ Scale pods เหล่านี้ ในบทความนี้ เราจะอธิบายวิธีการสร้างสถาปัตยกรรมที่ทำให้แอปพลิเคชันสามารถ Scale-down ได้อย่างราบรื่น และช่วยลดผลกระทบกับผู้ใช้งานให้น้อยที่สุด
บทความนี้แปลมาจาก How to rapidly scale your application with ALB on EKS (without losing traffic) โดยคุณ Yahav Biran, Sheetal Joshi และคุณ Yuval Dovrat
เพื่อให้การปิดใช้งานแอพลิเคชันเป็นไปได้อย่างสมบูรณ์นั้น จำเป็นต้องใช้การประกอบกันของการตั้งค่าของแอปพลิเคชัน Kubernetes และ Target group ซึ่ง AWS Load Balancer Controller รองรับการทำ Health check annotations เพื่อให้ตรงกับ pod readiness probe ที่บ่งชี้ว่า pod IP ที่ได้ลงทะเบียนไว้ใน target ของ ALB นั้นสถานะปกติพร้อมที่จะรับ Traffic ซึ่งในบทความนี้ เราจะแสดงให้เห็นถึงวิธีการแยก Application endpoint โดย Amazon Load Balancer health check ด้วย Kubernetes readiness probe และ PreStop hooks โดยการทำงานร่วมกันของทั้งคู่จะช่วยให้การปิดการทำงานของแอปพลิชันลงได้อย่างสมบูรณ์ นอกจากนั้น เราจะจำลองสถานการณ์การ Scale ขนาดใหญ่ที่มี Traffic ที่เข้ามาสูงสุดถึง 1,000 รายการพร้อมกัน และอธิบายวิธีการทำแต่ละขั้นตอน เพื่อลดการเกิด 50X HTTP error จากฝั่งผู้ใช้งาน
ตัวอย่างสถาปัตยกรรม
โค้ดตัวอย่างที่ใช้ deploy เป็นเว็บแอปพลิเคชันทำงานภายใต้ ALB และอธิบายวิธีการที่มีการ Failover ระหว่าง pods ในระหว่างการเหตุการณ์การ Scale-down ซึ่งแอปพลิเคชันจะใช้ฐานข้อมูลเพื่อเก็บข้อมูลรายการขนส่ง (Logistic) โดยเราจะสร้าง Cluster ของ Amazon Elastic Kubernetes Service (Amazon EKS) โดยใช้ VPC CNI สำหรับ pod networking และติดตั้ง AWS Load Balancer Controller add-on จากนั้นเราจะ Deploy Django แอปพลิเคชันง่าย ๆ เพื่อให้รองรับกับ Trafiic จาก Load simulator และเปลี่ยนแปลง ReplicaSet ของ Kubernetes deployment นอกจากนั้น เราจะ deploy cluster autoscaler ซึ่งจะเปลี่ยนขนาดของ Auto scaling group เพื่อให้เหมาะกับความต้องการในใช้งานของ Django pods เราจะทำการมอนิเตอร์สถานะของแอพลิเคชันระหว่างเหตุการณ์การทำ Scale-down
โค้ดตัวอย่าง
Deployment artifacts ทั้งหมด ได้เตรียมไว้ให้แล้วที่ Repository ของ aws-samples ซึ่งใน Repository ได้อธิบายวิธีการการติดตั้ง Infrastructure ที่จำเป็น รวมถึงฐานข้อมูล Logistics-db ไว้ด้วย โดยเริ่มต้นจากการ Deploy แอปพลิเคชัน Django Ingress โดยที่ยังไม่มี Health check และ Simulator app และเปิดใช้งาน Simulator ให้ทำงานประมาณ 30 นาทีเพื่อให้มีข้อมูลที่เพียงพอสำหรับการสร้างกราฟ ซึ่งรายละเอียดจะอยู่ในหัวข้อถัดไป
การประเมินผล
เริ่มต้นด้วยการสร้าง Amazon CloudWatch dashboard ใน Namespace “appsimulator” เพื่อมอนิเตอร์ Metrics ที่รายงานโดย Simulator โดยในกราฟแรกจะแสดงถึงจำนวนแอปพลิเคชัน pod และ Load simulator pod ในกราฟที่ 2 และ 3 แสดงตัวอย่างของจำนวน HTTP error codes ทั้งหมดในระหว่างช่วงเวลาการ Scale-down และกราฟสุดท้ายแสดงจำนวน node ของ Cluster ในแต่ล่ะช่วงเวลา
ในช่วง Peak มีทั้งหมด 623 simulation pod ทำงานอยู่บน t4g.xlarge C2 instance nodes ตามที่แสดงดังกราฟด้านล่าง ซึ่งจะเห็นว่าการเพิ่มขึ้นของ 50x HTTP error rate ระหว่างเหตุการณ์การ scale-down มีเปลี่ยนแปลงความต้องการของผู้ใช้
ในส่วนต่อไป เราจะอธิบายวิธีการใช้งาน Kubernetes PreStop hook, readiness probe, และ Health checks ด้วย AWS Load Balancer Controller เพื่อจัดการสัญญาณ SIGTERM ที่เกิดจาก pod termination โดยไม่ให้ส่งผลกระทบต่อผู้ใช้
วิธีการที่จะทำให้ไม่เกิด Error
เราสร้าง Application health functionality ใหม่กับ Signal handler จากนั้นไปตั้งค่า load balancer target group และ kubelet เพื่อให้ใช้ path ของ health อันใหม่
จะเห็นว่าเราเพิ่ม /logistics/health endpoint แยกออกมา และตั้งค่า Kubernetes ingress object ให้ใช้งาน health check endpoint ด้วย annotation alb.ingress.kubernetes.io/healthcheck-path และตั้งค่าระยะเวลาของการ probe ด้วย alb.ingress.kubernetes.io/healthcheck-interval-seconds เพื่อที่จะระบุ container ที่ไม่พร้อมใช้งาน
ตัวอย่างโค้ดบางส่วนจาก Kubernetes ingress spec
kind: Ingress
metadata:
name: django-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/healthcheck-path: /logistics/health
alb.ingress.kubernetes.io/success-codes: '200-301'
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '3'
ตัวอย่างโค้ดบางส่วนจาก Kubernetes deployment spec
readinessProbe:
httpGet:
path: /logistics/health
port: 8000
initialDelaySeconds: 3
periodSeconds: 3
Pod ได้รับสัญญาณ SIGTERM จาก kubelet เพราะ Kubernetes ต้องการที่จะหยุด pod เนื่องจากเหตุการณ์ node termination or scale เกิดขึ้น และ PreStop hook เป็นตัวช่วยที่ให้คุณสามารถทำ custom command ก่อนที่ SIGTERM จะถูกส่งไปที่ pod container โดยเมื่อ pod เริ่ม return 500 จากการ GET /logistics/health ทำให้ Readiness probe รู้ว่า pod นั้นไม่พร้อมที่จะรับ request เพิ่มเติมแล้ว และ Load Balancer Controller จะช่วยแก้ไข ALB เพื่อลบ target ที่ไม่พร้อมใช้งานนั้นทิ้งไป
ตัวอย่างโค้ดบางส่วนจาก Kubernetes deployment spec
:
preStop:
exec:
command: ["/bin/sh", "-c", "sed -i 's/health/nothealthy/g' /usr/src/app/logistics/health.py && sleep 120"]
ตอนนี้เราสามารถนำการแก้ไขตามที่แสดงข้างต้นมาใช้กับ Django ingress manifest ได้แล้ว ซึ่งอาจจะใช้เวลาประมาณ 30 นาทีในการที่ simulation จะสร้าง load ก่อนที่จะ scale down แอปพลิเคชัน
ผลการทดสอบ
จะเห็นว่าจำนวนของ Errors 504 ลดลงอย่างเห็นได้ชัด จากเฉลี่ย 340 ในระหว่างการ scale-down ไปเป็น 0 ในขณะที่จำนวนของ Errors 502 ลดลงจาก 200 เป็น 30 โดย 502 Error เหล่านี้ถูกพบจับโดย kubelet แต่ไม่ใช่ Error ที่เกิดขึ้นกับผู้ใช้งานที่เข้าใช้งานแอพลิเคชันผ่าน ALB
บทสรุป
บทความนี้แสดงให้เห็นว่า Amazon EKS และ AWS Load Balancer Controller ช่วยให้คุณสามารถจัดการกับการเปลี่ยนแปลงความต้องการการใช้งานของแอพลิเคชันโดยที่ไม่ส่งผลกระทบต่อผู้ใช้ โดยการทำงานร่วมกันของ Kubernetes PreStop hook และ readiness probe ด้วย health check endpoint คุณสามารถจัดการสัญญาณ SIGTERM ของแอปพลิเคชันของคุณได้อย่างเป็นอย่างดี
สามารถศึกษาเพิ่มเติมเกี่ยวกับ AWS Load Balancer Controller สำหรับรายการ Annotations ทั้งหมดที่สามารถใช้งานได้ ที่ได้ AWS Document
ท่านสามารถให้ข้อเสนอแนะ เสนอฟีเจอร์ใหม่ ๆ และดูรายละเอียด roadmaps ของเราได้ที่ AWS Containers Roadmap