AWS Thai Blog

ขยายจำนวน pod จากหลักร้อยไปหลักหมื่นบน Amazon EKS คลัสเตอร์

บทความนี้แปลมาจาก Scale from 100 to 10,000 pods on Amazon EKS ที่เขียนร่วมโดย Nikhil Sharma และ Ravishen Jain จาก OLX Autos กับ Akshaya Rawat จาก AWS

บทนำ

OLX Autos ทำการสร้างระบบสำหรับทีมนักพัฒนาภายในให้ใช้กันที่มีชื่อว่า ORION โดยระบบ ORION นั้นเป็นระบบที่มีไว้ใช้สร้างและรัน application สำหรับ non-prod environment ซึ่งระบบรองรับมากกว่า 100 environment ในช่วงเวลาเดียวกัน เพื่อที่ใช้ในการทดสอบ use case ที่แตกต่างกัน โดยในแต่ละ environment จะมีจำนวน pod ที่รันมากกว่า 100 ตัว ด้วย Amazon Elastic Kubernetes Service (Amazon EKS) จุดประสงค์ที่มีการสร้าง environment ขึ้นมามากมายนั้นก็เพื่อให้นักพัฒนาสามารถทำการทดสอบ feature ใหม่ๆ ได้พร้อมกัน ส่วน environment ที่ไม่ได้ใช้งานแล้วก็จะถูกทำลายทิ้ง ซึ่งทางทีมวิศวกรของ OLX Autos เลยตัดสินใจ ใช้ Amazon EKS เพียงแค่ 1 คลัสเตอร์ ในการโฮส environment ทั้งหมด เพื่อที่จะสามารถใช้ทรัพยากรให้มีประสิทธิภาพดีขึ้น พวกเขายังเลือกใช้ spot อินสแตนซ์ สำหรับ Amazon EKS เพื่อช่วยประหยัดค่าใช้จ่ายลงได้อย่างมาก ในบางช่วงเวลาระบบ ORION นั้นต้องรองรับจำนวน pod มากกว่า 10,000 ตัว ที่รันอยู่บนคลัสเตอร์เดียวกัน แถมยังต้องรองรับการสร้าง environment ใหม่ๆ ตามความต้องการของทีมนักพัฒนาอีกด้วย

ในบทความนี้ ทางทีมวิศวกรของ OLX Autos ได้อธิบายว่าพวกเขาเจออุปสรรคอะไรบ้างและแก้ปัญหาอย่างไรจึงสามารถขยายจำนวน pod ที่รันบน Amazon EKS คลัสเตอร์ จาก 100 ไปจนมากกว่า 10,000 ตัวได้

ก่อนอื่นมาทำความรู้จักกับ OLX Autos

OLX Autos เป็นบริษัทลูกของ OLX Group ทำระบบซื้อขายยานพาหนะมือสองและขยายธุรกิจไปในหลายประเทศ จุดเด่นของแพลตฟอร์มคือเป็นระบบที่ช่วยสร้างความมั่นใจ สะดวก และทำธุรกรรมจบในที่เดียวทั้งสำหรับผู้ซื้อและผู้ขาย OLX Autos จัดเป็นบริษัทที่ทำการปฏิรูปวงการซื้อขายรถยนต์มือสอง โดยรวมประสบการณ์การซื้อขายรถยนต์มือสองผ่านทางออน์ไลน์และออฟไลน์เข้าด้วยกัน ซึ่งปัจจุบัน OLX Autos ก็ขยายธุรกิจไปถึง 11 ประเทศแล้ว

อะไรคือ OLX Autos IDP – Orion

ทีมวิศวกรของ OLX Autos ได้ทำการสร้าง environment ที่ชื่อว่า Roadster ไว้สำหรับโฮส application สำหรับธุรกิจในหลายภาคส่วน อย่างเช่น ซื้อขายรถยนต์ การเงิน และการตรวจสอบ โดย environment ที่ใช้ต้องมีคุณสมบัติที่ทำงานได้เร็ว สามารถแตกเป็นโมดูลย่อยๆได้ และระบบสามารถฟื้นกลับมาทำงานใหม่ได้เมื่อระบบผิดปกติ รวมถึงเลือกใช้เทคโนโลยีที่มีความล้ำสมัย เพื่อช่วยให้ OLX Autos ยังเป็นผู้นำในตลาดซื้อขายรถยนต์มือสอง ซึ่งมีการแข่งขันกันที่ดุเดือนเป็นปกติอยู่แล้ว ท้ายสุดทีมวิศวกรได้เลือก Amazon EKS มาใช้งานในการโฮส Roadster environment เพราะสามารถตอบโจทย์คุณสมบัติตามที่ต้องการได้ตามที่กล่าวมา

เนื่องจาก OLX Autos ทำการขยายฐานลูกค้าสม่ำเสมอ ทำให้การส่งมอบ feature ใหม่ๆให้ทันหรือก่อนคู่แข่งนั้น ถือเป็นความท้าทายที่สำคัญ เพราะฉะนั้นการช่วยลดความซับซ้อน และเพิ่มประสิทธิภาพการทำงานของทีมนักพัฒนา เป็นเป้าหมายหลักของทีมวิศวกรที่ดูแล Roadster environment ตามที่ได้กล่าวมาก่อนหน้านี้ทีมวิศวกรต้องสร้าง Roadster ขึ้นมาหลายๆ environment สำหรับใช้ทดสอบ use case ต่างๆ รวมทั้งการทำ automated test สำหรับการทดสอบในตลาดลูกค้าใหม่ๆ โดยในหนึ่ง Roadster environment จะประกอบไปด้วยหลากหลาย micro service รวมถึงฐานข้อมูล​ ซึ่งต้องทำงานควบคู่กันในแต่ละ use case

เป็นที่ทราบกันดีว่าการสร้างและดูแล Roadster environment เป็นงานที่ต้องใช้เวลาและทรัพยากรมาก ทางทีมวิศวกรจึงสร้างระบบ Internal Developer Platform (IDP) หรือ Orion ขึ้นมาเพื่อเป็น platform ตัวกลางเพื่ออำนวยความสะดวกในการสร้าง Roadster environment ให้แต่ละทีมที่ใช้งาน

Solution overview

แผนภาพด้านล่างแสดง architecture ของระบบ Orion

โดยระบบ Orion ถูกออกแบบมาเพื่อที่จะ

  • ลดความซับซ้อนของทีมนักพัฒนา โดยรวบรวมแต่ละ service กับเครื่องมือต่างๆ ให้สามารถเข้าถึงและใช้งานได้อย่างราบรื่น
  • ช่วยทีมนักพัฒนาสามารถสร้าง Roadster environment ขึ้นมาได้เองโดยที่ไม่ต้องพึ่งทีมงานที่ดูแล โดยสามารถสร้าง Roadster environment ผ่านการคลิ๊กเพียงแค่ไม่กี่ครั้ง

Amazon EKS ถูกเลือกมาใช้ในการรันระบบ IDP (Orion)

ใน Roadster environment นั้น application เป็น container ทั้งหมดและรันบน Amazon EKS มานานนับปี ซึ่ง Amazon EKS ก็เป็นตัวเลือกที่ตอบโจทย์สำหรับ Orion ในการนำมาใช้สร้าง Roadster environment ที่มีมากกว่า 100 environment โดยใช้ Amazon EKS เพียงคลัสเดียวในการโฮส environment ทั้งหมด

จากภาพด้านล่างแสดงให้เห็นจำนวนทรัพยากรที่ Orion ดูแลและจัดการบน Amazon EKS คลัสเตอร์

อย่างไรก็ดี ตามที่ระบบ ORION เริ่มถูกใช้งานมากขึ้น ทางทีมก็เริ่มเจออุปสรรคต่างๆ จากการรัน Roadster environment ที่มีจำนวนมากขึ้น

ทางทีมของ OLX Autos เลยถือโอกาสแบ่งปันข้อมูลเกี่ยวปัญหาที่พบเจอและแนวทางการแก้ไข ดังต่อไปนี้

ปัญหา latency ที่สูงขึ้นของ DNS resolution

ปัญหาแรกที่เจอคือเรื่อง classic ndots โดยปกติค่าตั้งต้นของ ndot คือ 5 ที่ถูกเซ็ตไว้ใน Amazon EKS ตามมาตรฐาน DNS โดเมนเนมจะถูกมองเป็น FQDN ถ้าจำนวน dot(.) เท่ากับค่าของ ndot หรือโดเมนเนมที่มี dot ปิดท้าย ในกรณีที่คิวรี DNS ของโดเมนเนมที่ไม่มี dot ปิดท้าย core-dns จะต้องทำการวนหาทุกโดเมนเนมที่เป็นไปได้จนกว่าจะครบหรือสำเร็จ

ยกตัวอย่างเช่น ถ้าทำการคิวรี amazon.com จากบน pod core-dns จะทำการคิวรีโดเมนเนมดังต่อไปนี้

[amazon.com.default.svc.cluster.local,

amazon.com.svc.cluster.local,

amazon.com.cluster.local,

amazon.com.]

โดยเรียงเป็นลำดับ หรือจนกว่าจะได้ผลลัพธ์ที่สำเร็จ

ทางทีมวิศวกรของ ORION ได้ทำการทดสอบ nslookup ด้วย amazon.com บน worker node ของ Amazon EKS คลัสเตอร์ ผลที่ได้คือมีการยิง DNS question ไป 7 ครั้งโดย 5 ไม่ได้คำตอบ และอีก 2 ครั้งได้กลับมาเป็นของ IPv4 กับ IPv6

จากสกรีนช็อตด้านล่างแสดงผลลัพธ์ที่ได้จากการรันคำสั่ง nslookup กับ amazon.com และทำการนับจำนวนการคิวรี DNS และ error ที่เกิดขึ้นจากการคิวรี DNS โดยใช้คำสั่ง grep QUESTIONS และ grep NXDOMAIN ตามลำดับ

เนื่องจากระบบ Orion มีขนาดใหญ่ขึ้น การคุยข้าม service กันก็มีมากขึ้นตาม ส่งผลให้จำนวนการคิวรี DNS ก็ถี่ขึ้นตาม ถ้าค่าคอนฟิคของ ndot คือ 5 ก็จะทำให้มีการคิวรีเพิ่มขึ้น 5 เท่า และผลกระทบที่ตามมาก็คือ core-dns นั้น crashed และทำให้พบ error จากการแปลงโดเมนเนมเป็นไอพีแอดเดรสบ่อยครั้ง ถ้าสนใจเพิ่มเติม สามารถศึกษาเกี่ยวกับผลกระทบที่เกิดจาก ndot บน Kubernetes เพิ่มเติมได้จากบทความนี้

Response time สูงขึ้นเนื่องจาก CPU throttling

โดยเริ่มแรกทางทีมวิศวกรของ OLX Autos ทำการกำหนดค่า CPU limit ของ pod ซึ่ง CPU Limit เป็นตัวกำหนดว่า container สามารถใช้ CPU time ได้เท่าไร และการที่กำหนดค่า CPU limit ยิ่งทำให้ปัญหาเรื่อง ndot แย่ลงเข้าไปใหญ่ จากที่ได้กล่าวมาก่อนหน้านี้ทุกการคิวรี DNS มีโอกาสจะไม่ได้ผลลัพธ์ก่อนที่จะได้ครั้งที่สำเร็จ และ CPU limit ดันไปควบคุมจำนวนของ CPU time ทำให้ container อาจต้องรอโอกาสของ CPU cycle ในรอบถัดๆ ไป ในการทำวนคิวรี DNS ซ้ำจนกว่าจะสำเร็จ ถ้ากลไกดังกล่าวเกิดขึ้นซ้ำๆ บ่อยครั้งส่งผลให้ application มีประสิทธิภาพที่แย่ลงรวมถึง latency ที่สูงขึ้นด้วย ทางทีมวิศวกรเลยทำการแก้ไขค่า CPU limit กลับไปเป็นค่าตั้งต้น โดย Eric Kuhn ได้ทำการอธิบายเกี่ยวกับผลกระทบจากการตั้งค่า CPU limit ไว้ในบทความนี้

แนวทางการแก้ปัญหา ndot โดยเพิ่ม dot ไปที่ท้ายของโดเมนเนม

การที่ต่อท้าย dot ไปที่โดเมนเนม ทำให้โดเมนเนมถูกมองเป็น FQDN ส่งผลให้ตอนทำการคิวรี DNS จะไม่วนหาไอพีแอดเดรสจาก search path ซึ่งช่วยให้ลดจำนวนการคิวรี DNS ลง

ทีมงานได้ทำการทดสอบรันคำสั่ง nslookup ด้วย amazon.com ผลที่ได้ปรากฏว่าจำนวน DNS question ลดจาก 7 มาเหลือแค่ 2 ครั้งและไม่มี error จาก NXDOMAIN เลย ซึ่งวิธีนี้ช่วยลดจำนวนคิวรีที่เกิดขึ้นแก่ core-dns ได้มากกว่า 70%

จากสกรีนช็อตด้านล่างแสดงให้เห็นผลลัพธ์จากการรันคำสั่ง nslookup ด้วย amazon.com.

โดยทางทีมได้เพิ่ม dot ต่อท้ายเข้าไปกับ http endpoint ของแต่ละ service ผ่านการตั้งค่าให้กับ environment variable

ทำ DNS cache เพื่อลด latency ลงได้อีก

ระบบ Orion นั้นมีสเกลที่ใหญ่ การเพิ่ม dot ต่อท้ายโดเมนเนมนั้นยังไม่สามารถแก้ปัญหา latency ที่สูงได้หมดไป ทีมวิศวกรของ OLX ได้ประยุกต์ใช้ NodeLocal DNSCache agent ที่พัฒนาโดยคอมมูนิตี้ของ K8S เอง การนำ feature นี้มาใช้ช่วยให้ application ทำงานได้เร็วขึ้น

จากภาพด้านล่างแสดงให้เห็น response time ระหว่างใช้กับไม่ใช้คุณสมบัตินี้

ปัญหาการขาดแคลนของ IP กับการใช้งาน VPC CNI ปลั๊กอิน

สำหรับ VPC CNI ปลั๊กอิน ถูกรันในรูปแบบ daemonset โดยมีหน้าที่ในการจัดหาไอพีแอดเดรสที่ว่างใน Amazon VPC ให้แก่ pod โดยแรกเริ่ม VPC CNI จะทำการเพิ่ม ENI อีกหนึ่งตัวให้กับ worker node เป็นทั้งหมด 2 ตัว และทำการจองไอพีแอดเดรสจำนวนหนึ่งไว้ด้วย

ซึ่งจำนวนของไอพีแอดเดรสที่ใช้ได้ ขึ้นอยู่กับ instance type ของเครื่อง ซึ่งสามารถเช็คเพิ่มเติมได้ว่า instance type แต่ละประเภทสามารถรองรับจำนวน ENI ได้เท่าไรต่อเครื่อง และในหนึ่ง ENI สามารถรองรับจำนวนไอพีแอดเดรสได้เท่าไรจากเอกสารนี้

เพราะ​ฉะนั้นเราสามารถตีความได้ว่า เครื่องที่มี instance type เป็น c5.9xlarge จะทำการจองไอพีแอดเดรสอยู่ที่ 58 ไอพี (29 ไอพีต่อ 1 ENI) จาก VPC pool ถึงแม้จะไม่มี pod รันอยู่บนเครื่องนั้นๆ ก็ตาม

ซึ่งผลกระทบที่เกิดขึ้นก็คือไอพีแอดเดรสจะเกิดการขาดแคลนใน VPC และ Amazon EKS คลัสเตอร์จะไม่สามารถเพิ่มเครื่องเข้ามาใหม่ได้ รวมถึง AWS resources อื่นๆใน VPC เดียวกันก็ไม่สามารถถูกสร้างได้เช่นกัน

อย่างไรก็ตาม เราสามารถตั้งค่าจำนวนไอพีและ ENI ที่ถูกจองโดย VPC CNI ปลั๊กอิน ผ่าน parameter ของปลั๊กอินได้ดังต่อไปนี้

– MINIMUM_IP_TARGET คือจำนวนขั้นต่ำที่ไอพีจะถูกจองไว้ให้แต่ละเครื่อง

– WARM_IP_TARGET คือจำนวนสูงสุดของไอพีที่จองไว้ได้แม้ยังไม่ได้ถูกใช้งานของแต่ละเครื่อง

– WARM_ENI_TARGET คือจำนวน ENI ที่สามารถผูกกับเครื่องได้

อันดับแรกใช้ WARM_IP_TARGET เพื่อลดจำนวนไอพีที่ถูกจองไว้แต่ยังไม่ใช้งานลง

เริ่มแรก ทางทีมงานตั้งค่า WARM_IP_TARGET = 1 ซึ่งจะทำให้มีแค่ไอพีเดียวที่ถูกจองไว้

โดยสามารถรันคำสั่งตามด้านล่าง เพื่อตรวจสอบจำนวนไอพีที่ถูกใช้งานและถูกจองไว้บนเครื่องนั้นๆ

kubectl exec -it <aws-node-pod-name> -c aws-node -- curl localhost:61679/v1/enis

จากรูปแสดงผลลัพธ์ของคำสั่งที่รันด้านบน

จากการตั้งค่าของก่อนหน้า ช่วยแก้ปัญหาไอพีขาดแคลนได้จริง แต่กลับก่อให้เกิดอีกปัญหาหนึ่งแทน เนื่องจากมีแค่หนึ่งไอพีที่ถูกสำรองไว้ (WARM_IP_TARGET=1) เมื่อไรก็ตามที่มี pod จำนวนมากถูกสร้างขึ้น จำนวนไอพีก็จะถูกขอใช้เป็นจำนวนมากเช่นกัน ส่งผลให้เกิดสถานการณ์การแย่งไอพีกัน ทำให้ pod ต้องรอ VPC CNI ปลั๊กอินทำการแจกจ่ายไอพีแอดเดรสให้ worker node ก่อน ในจังหวะนี้ error ที่ทางทีมเจอคือ ‘failed to assign an IP address to container and DataStore has no available IP addresses’ (ไม่สามารถกำหนดไอพีให้แก่ container ได้ เพราะไม่มีไอพีแอดเดรสเหลืออยู่)

โดยสามารถเช็ค error event ได้จากคำสั่ง kubectl describe pod <pod_name>

Warning FailedCreatePodSandBox 59s kubelet
Failed to create pod sandbox: rpc error: code = Unknown desc failed to
set up sandbox container

"42c567cfd18ffe01a6fa5f38574a4120d486cd20058b20bf3646a3236f198b65" network
for pod "ca9efe75-2a23-4da7-9752-8d7541ed6e92-8zq5s": networkPlugin cni
failed to set up pod "ca9efe75-2a23-4da7-9752-8d7541ed6e92-8zq5s_staging"
network: add cmd: failed to assign an IP address to container

หรือจากไฟล์ log ที่ /var/log/aws-routed-eni/ipamd.log ของ worker node

{"level":"debug","ts":"2022-02-02T05:28:21.576Z","caller":"rpc/rpc.pb.go:486",
"msg":"AddNetworkRequest: ClientVersion:\"v1.7.5\" K8S_POD_NAME:\"nginx-2\"
KBS_POD_NAMESPACE:\"default\"
KBS_POD_INFRA_CONTAINER_ID:\"42b261766a518973ad2bdfa33948e745da823f1e132cdca2b862dd4e27d4f567\"
ContainerID:\"42b261766a518973ad2bdfa33948e745da823f1e132cdca2b862dd4e27d4f567\"
IfName:\"eth0\" NetworkName:\"aws-cni\" Netns: \"/proc/20244/ns/net\" "}
{"level":"debug","ts":"2022-02-02T05:28:21.576Z","caller": "ipamd/rpc_handler.go:142",
"msg":"AssignIPv4Address: IP address pool stats: total: 3, assigned 3"}

{"level":"debug","ts":"2022-02-02T05:28:21.576Z","caller":"ipamd/rpc_handler.go:142",
"msg":"AssignPodIPv4Address: ENI eni-067be541f80752bfb does not have available addresses"}

{"level": "error", "ts":"2022-02-02T05:28:21.576Z","caller":"ipamd/rpc_handler.go:142",
"msg":"Datastore has no available IP addresses"}

แก้ไขโดยการตั้งค่า MINIMUM_IP_TARGET เพื่อจองจำนวนไอพีไว้ล่วงหน้าได้

ในการแก้ปัญหาข้างต้น ทีมงานทำการตั้งค่า MINIMUM_TARGET ให้เท่ากับจำนวน pod ที่คาดว่าจะรันบนแต่ละเครื่อง ซึ่งรวมถึงจำนวน daemonset ที่จะรันในคลัสเตอร์ด้วย โดยสรุปในการแก้ปัญหาเรื่องไอพีขาดแคลนนั้น สามารถแก้ได้โดยตั้งค่า WARM_IP_TARGET ให้เท่ากับ 1 กับ MINIMUM_IP_TARGET เท่ากับจำนวน pod ที่คาดว่าจะรันของแต่ละ worker node

ปัญหาของการใช้ Spot แบบ 100%

อย่างที่ทราบกันดีว่าทีม OLX Autos ใช้ Amazon EKS คลัสเตอร์ ในการรันระบบ Orion นอกจากนี้ยังใช้ Spot fleet เพื่อช่วยประหยัดค่าใช้จ่ายได้เป็นอย่างมาก แต่อย่างไรก็ดีมีบางเรื่องที่ต้องคำนึงถึงดังต่อไปนี้

กรณี Spot อินสแตนซ์ไม่มีให้ใช้งาน

ทีมงาน OLX Autos ต้องมั่นใจว่า ระบบยังสามารถทำงานต่อไปโดยไม่กระทบกับ Roadster environment ที่รันอยู่ จากกรณีที่ Spot อินสแตนซ์ถูกขอคืนจาก AWS ถึงแม้จะไม่ใช่ production environment ทางทีมนักพัฒนาของ OLX Autos ต้องสามารถใช้งาน environment ของตัวเองได้อยู่ตลอดเวลา เพื่อที่จะเพิ่มโอกาสในการใช้งาน Spot อินสแตนซ์ทางทีมเลือกใช้ instance type หลากหลายประเภทที่มีขนาด ซีพียูและ หน่วยความจำที่เท่ากัน เช่น m5.2xlarge, m5a.2xlarge, m5d.2xlarge, m5ad.2xlarge และ m4.2xlarge นอกเหนือไปกว่านั้น ทีมยังเลือกใช้ Priority expander ของ Cluster-autoscaler เพื่อให้ระบบสามารถกลับมาใช้ on-demand อินสแตนซ์แทนได้ ถ้าไม่มี Spot อินสแตนซ์ว่างให้ใช้

ตัวอย่าง ConfigMap ของ Cluster Autoscaler ที่ทางทีม OLX Autos ใช้

apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-autoscaler-priority-expander
  namespace: kube-system
data:
  priorities: |-
   5:
     - .*on-demand.*
   50:
     - .*spot.*

จากตัวอย่างข้างต้น ทางทีมมีการเลือกใช้ nodegroup มากกว่า 1 ชุด เพื่อให้สามารถเลือกใช้งานได้ทั้ง spot และ on-demand อินสแตนซ์ โดยใช้ชื่อของ nodegroup ในการแยกประเภทของอินสแตนซ์ ตัวอย่างเช่น ชื่อ nodegroup ที่มี spot รวมอยู่ด้วย จะใช้งาน spot อินสแตนซ์ ส่วนที่มี on-demand จะใช้ on-demand อินสแตนซ์ ในส่วน priorities จะเห็นได้ว่า nodegroup ของ spot จะมี priority ที่สูงกว่าของ on-demand ทำให้ Cluster Autoscaler จะเลือกใช้ spot อินสแตนซ์ก่อน แต่ถ้า spot ไม่มีให้ใช้ Cluster Autoscaler จะไปสร้าง on-demand อินสแตนซ์แทน นอกจากนี้ยังทำการแก้ไขค่า timeout ของ max-node-provision-time จาก 15 นาทีเป็น 10 นาทีเพื่อลดเวลาในการสลับกลับไปใช้ on-demand ถ้าเลี่ยงไม่ได้

ในอนาคตทาง OLX Autos มีแผนที่จะใช้ Karpenter เพื่อจัดการในเรื่องของ autoscaling และ spot อินสแตนซ์ ซึ่ง Karpenter เป็น cluster-autoscaler ประเภทหนึ่ง ที่ช่วยให้คลัสเตอร์สามารถที่จะเพิ่มหรือลดจำนวนเครื่องในคลัสเตอร์ได้เร็วขึ้น ทาง AWS ได้ประกาศ พร้อมใช้งานแล้วเมื่อ re:Invent 2021 โดยสามารถเช็คเพิ่มเติมได้จากบทความนี้

รับมือกับ Spot termination

เนื่องจากทีมวิศวกรเลือกใช้ Self-managed nodes ทำให้ต้องจัดการ EC2 termination เอง แต่อย่างไรก็ตาม aws-node-termination-handler (NTH) ถูกสร้างมาเพื่อช่วยอำนวยความสะดวกในเรื่องนี้ โดยหลักการ NTH จะทำการมอนิเตอร์ ด้วยการยิงเช็คไปที่ /spot กับ /events endpoint เพื่อเช็คว่าเครื่องกำลังจะถูกยึดคืนหรือไม่ ถ้าเมื่อไรที่เหตุการณ์นั้นเกิดขึ้น NTH จะแยกเครื่องนั้นออกจากคลัสเตอร์ เพื่อไม่ให้มี workload ใหม่มารัน รวมทั้ง pod ที่รันอยู่ก็จะถูกย้ายออกไปเหมือนกัน โดย NTH สามารถติดตั้งง่ายโดยใช้ Helm ซึ่งสามารถดูตัวอย่างได้จากลิงค์นี้

ใช้ทรัพยากรที่จองไว้ให้มีประสิทธิภาพยิ่งขึ้น

จากที่ทางทีมงานใช้ nodegroup หลายชุด ซึ่งแต่ละชุดประกอบไปด้วย instance type หลากหลายที่มีจำนวนทรัพยากรที่เท่ากัน ยกตัวอย่างเช่นถ้าต้องการ 4 vCPU และ 16 GiB RAM ใน nodegroup นั้น ก็สามารถเลือกใช้งาน m5a.xlarge m4.xlarge m5.xlarge และm5d.xlarge ได้ ในขณะเดียวกันถ้าต้องการ nodegroup ที่มีทรัพยากรใหญ่ขึ้นก็สามารถเลือกใช้ขนาดอย่าง 9xlarge เพื่อเลือกใช้ครื่องที่เหมาะสมกับ workload ที่ต้องการรัน ทาง Cluster Autoscaler ก็มีตัวเลือกของ expander อย่าง least-waste ให้เลือกใช้

สกรีนช็อตด้านล่างเป็นตัวอย่างคอนฟิคที่เกี่ยวข้องของ Cluster Autoscaler

โดยค่าเริ่มต้นของ expander จะเป็น random ซึ่ง Cluster Autoscaler จะสร้างเครื่องเข้าไปใน nodegroup แบบสุ่ม นอกจากนั้นทางทีมยังใช้ Cloudability ในการตรวจสอบค่าใช้จ่ายที่เกิดขึ้น รวมถึง NewRelic ในการมอนิเตอร์การใช้งานทรัพยากรต่างๆที่เกิดขึ้น เพื่อที่ทีมสามารถที่จะทำ right sizing ของทรัพยากร ให้เหมาะกับ application ได้อย่างมีประสิทธิภาพ

ปัญหาของ pod ที่ต้องรันงานที่มีความสำคัญสูง

อีกหน้าที่หนึ่งของ Amazon EKS คลัสเตอร์ ที่นอกจากทำการโฮสระบบ Orion แล้ว ยังทำการโฮส CI/CD pipeline อีกด้วย เพื่อใช้ในการดีพลอยงานต่างๆ นอกจากใช้งานในการดีพลอยแล้ว CI/CD pipeline ยังถูกติดตั้งสำหรับการทำลาย environment ทิ้งด้วย ซึ่ง pod ที่ใช้สำหรับรัน CI/CD pipeline นั้นมีความสำคัญมาก เพราะถ้าไม่มี pod สำหรับ CI/CD pipeline รันอยู่ ก็เป็นเหตุให้ทีมอื่นๆไม่สามารถทำงานต่อได้เพราะ Roadster environment ถูกสร้างขึ้นมาไม่ได้ บางสถานะการณ์ pod ที่ทำหน้าที่สำหรับ CI/CD pipeline อาจจะถูกดึงออกจากคลัสเตอร์ได้ ยกตัวอย่างเช่น ตอนสร้าง Roadster environment ใหม่จะมีจำนวน pod ที่ถูกสร้างขึ้นมาพร้อมกันเป็นร้อยๆ ตัว ทำให้บางจังหวะที่ Cluster Autoscaler จะทำการเพิ่มเครื่องเข้าในคลัสเตอร์ บางครั้งก็จะมีโอกาสเจอ InsufficientInstanceCapacity สำหรับ spot อินสแตนซ์ และมีโอกาสที่ pod ซึ่งรัน CI/CD pipeline อยู่อาจถูกดึงออกจากคลัสเตอร์ได้

ทีมวิศวกรของ OLX Autos แก้ปัญหาโดยการกำหนด pod priority ให้เป็น Non-preempting PriorityClass ทำให้ pod ที่รัน CI/CD pipeline ไม่ถูกเด้งออกและพร้อมใช้งานตลอดเวลา

จากตัวอย่างด้านล่างเป็นคอนฟิค PriorityClass ของ K8S ที่ preemtionPolicy มีค่าเป็น Never

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority-nonpreemptive
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "This priority class will not cause other pods to be preempted."

คอนฟิคของ pod ตามด้านล่าง ใช้ priorityClass ที่ถูกสร้างมาก่อนหน้านี้

apiVersion: v1
kind: Pod
metadata:
  name: gitlab-runner
spec:
  containers:
  - name: gitlab-runner
    image: gitlab/gitlab-runner
  priorityClassName: high-priority-nonpreempting

กล่าวโดยสรุป

ทางทีมวิศวกรของ OLX Autos อธิบายถึงวิธีการที่ช่วยให้ Amazon EKS คลัสเตอร์สามารถที่จะรองรับจำนวน pod เป็นหลักหมื่นได้ ซึ่งระบบ Orion ช่วยให้ทีมนักพัฒนาของ OLX Autos สามารถพัฒนา feature ใหม่ๆที่มีความสำคัญต่อการขยายฐานลูกค้าไปในหลายๆประเทศ รวมถึงสร้างสรรค์โมเดลธุรกิจใหม่ๆ โดยที่แต่ละทีมสามารถที่จะมี Roadster environment สำหรับใช้พัฒนาและทดสอบเป็นของตัวเอง นอกจากนั้น Amazon EKS ยังช่วยให้ทีมงานสามารถใช้ทรัพยากรให้มีประสิทธิภาพที่ดียิ่งขึ้น ด้วยการนำ spot อินสแตนซ์ มาใช้เพื่อลดค่าใช้จ่าย

สรุปประเด็นสำคัญที่ได้จากประสบการณ์ครั้งนี้ได้แก่

  1. Application latency ลดลงจาก 3000 ms มา 50 ms โดยดีขึ้นประมาณ 98% ด้วยวิธีเพิ่ม dot ต่อท้าย FQDN และการทำ DNS caching
  2. ค่าคอนฟิคตั้งต้นของ VPC CNI ปลั๊กอิน ถูกเซ็ตมาให้จองไอพีล่วงหน้าไว้ ทำให้สามารถสร้าง pod ได้ไว แต่ผลที่ตามมาอาจจะเจอเรื่องไอพีขาดแคลนแทน เพราะฉะนั้น ควรแก้ไขค่าพารามิเตอร์ของปลั๊กอินให้สอดคล้องกับจำนวน pod ที่รันบนแต่ละ worker node รวมถึงกำหนดให้จองไอพีได้เพียงหนึ่งหมายเลขด้วย
  3. Spot อินสแตนซ์ช่วยประหยัดค่าใช้จ่ายได้ถึง 90% และเหมาะนำมาใช้กับ non-prod environment รวมถึง priority expander ที่เข้ามาช่วยให้คลัสเตอร์มีความเสถียร​โดยนำ on-demand อินสแตนซ์มาร่วมใช้งานด้วย และ least-waste expander ที่ทำให้ระบบสามารถใช้ทรัพยากรได้เต็มที่
  4. PriorityClass ถูกนำมาใช้สำหรับ pod ที่ต้องรันงานที่มีความสำคัญสูง โดยเฉพาะ pod ที่ไม่สามารถถูกดึงออกหรือรบกวนจากคลัสเตอร์ได้เลย โดยสามารถตั้งเป็น non-preempting PriorityClass ได้