ภาพรวมสั้นๆ ของปัญหา วันหนึ่งระหว่างการอัปเดตคลัสเตอร์ k8s ตามแผน เราพบว่า POD เกือบทั้งหมดของเรา (ประมาณ 500 จาก 1,000) ในโหนดใหม่ไม่สามารถเริ่มทำงานได้ และนาทีก็กลายเป็นชั่วโมงอย่างรวดเร็ว เราพยายามค้นหาสาเหตุที่แท้จริง แต่หลังจากผ่านไปสามชั่วโมง PODS ยังคงอยู่ในสถานะ ContainerCreating โชคดีที่นี่ไม่ใช่สภาพแวดล้อมการผลิตและหน้าต่างการบำรุงรักษาถูกกำหนดไว้ในช่วงสุดสัปดาห์ เรามีเวลาตรวจสอบปัญหาโดยไม่มีแรงกดดันใดๆ คุณควรเริ่มค้นหาสาเหตุที่แท้จริงจากที่ไหน คุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีแก้ปัญหาที่เราพบหรือไม่ เตรียมตัวให้พร้อมและสนุกไปกับมัน! รายละเอียดเพิ่มเติมเกี่ยวกับปัญหา ปัญหาคือเรามีภาพ Docker จำนวนมากที่ต้องดึงและเริ่มต้นบนแต่ละโหนดในคลัสเตอร์ในเวลาเดียวกัน เนื่องจากการดึงภาพ Docker พร้อมกันหลายรายการบนโหนดเดียวอาจทำให้มีการใช้งานดิสก์สูงและเวลาเริ่มต้นระบบแบบเย็นยาวนานขึ้น บางครั้งกระบวนการ CD อาจใช้เวลานานถึง 3 ชั่วโมงในการดึงภาพออกมา อย่างไรก็ตาม ในครั้งนี้ กระบวนการดังกล่าวเกิดการหยุดชะงัก เนื่องจากปริมาณ PODS ในระหว่างการอัปเกรด EKS (แบบอินไลน์ เมื่อเราแทนที่โหนดทั้งหมดในคลัสเตอร์) สูงเกินไป แอปทั้งหมดของเราอยู่ใน k8s (ตาม ) เพื่อประหยัดต้นทุนสำหรับสภาพแวดล้อม DEV เราจึงใช้อินสแตนซ์จุด EKS เราใช้อิมเมจ สำหรับโหนด AmazonLinux2 เรามี (FB) จำนวนมากในสภาพแวดล้อมการพัฒนาที่ปรับใช้กับคลัสเตอร์ Kubernetes ของเราอย่างต่อเนื่อง FB แต่ละรายการมีชุดแอปพลิเคชันของตัวเอง และแอปพลิเคชันแต่ละรายการมีชุดการอ้างอิงของตัวเอง (ภายในอิมเมจ) ฟีเจอร์สาขา ในโครงการของเรา มีแอปเกือบ 200 แอป และจำนวนนี้ยังคงเพิ่มขึ้นเรื่อยๆ แอปแต่ละตัวจะใช้หนึ่งใน 7 อิมเมจพื้นฐานของ Docker ที่มีขนาดประมาณ 2 GB ขนาดรวมสูงสุดของอิมเมจที่เก็บถาวร (ใน ) อยู่ที่ประมาณ 3 GB ECR รูปภาพทั้งหมดถูกเก็บไว้ใน Amazon Elastic Container Registry (ECR) เราใช้ประเภทปริมาณ gp3 EBS เริ่มต้นสำหรับโหนด ปัญหาที่ต้องเผชิญ การเริ่มพ็อดใหม่ด้วยภาพใหม่นั้นอาจใช้เวลานานกว่า 1 ชั่วโมง โดยเฉพาะอย่างยิ่งเมื่อมีการดึงภาพหลายภาพพร้อมกันบนโหนดเดียว ระยะเวลาการเริ่มต้นแบบเย็นที่ขยายออก: เกิด บ่อยครั้ง หรือติดอยู่ในสถานะ บ่งชี้ถึงปัญหาในการดึงภาพ ข้อผิดพลาด ErrImagePull: ErrImagePull ContainerCreating การใช้ดิสก์ยังคงอยู่ที่เกือบ 100% ในระหว่างกระบวนการดึงภาพ ซึ่งเป็นผลมาจากการใช้ดิสก์ I/O จำนวนมากที่จำเป็นสำหรับการคลายการบีบอัด (เช่น “unpigz”) การใช้ดิสก์สูง: ชุด DaemonSet ของระบบบางชุด (เช่น หรือ ) ถูกย้ายไปยังสถานะ "ไม่พร้อม" เนื่องจากแรงกดดันของดิสก์ ซึ่งส่งผลกระทบต่อความพร้อมของโหนด ปัญหาชุด DaemonSet ของระบบ: aws-node ebs-csi-node เนื่องจากเราใช้อินสแตนซ์จุด เราจึงไม่สามารถใช้ดิสก์ภายในเครื่องเพื่อแคชรูปภาพได้ ไม่มีแคชรูปภาพบนโหนด: ส่งผลให้การปรับใช้บนสาขาฟีเจอร์ต่างๆ หยุดชะงักเป็นจำนวนมาก โดยเฉพาะอย่างยิ่ง เนื่องจาก FB ที่แตกต่างกันมีชุดรูปภาพพื้นฐานที่แตกต่างกัน หลังจากตรวจสอบอย่างรวดเร็ว เราพบว่าปัญหาหลักคือแรงกดดันของดิสก์บนโหนดโดยกระบวนการ กระบวนการนี้รับผิดชอบในการคลายการบีบอัดอิมเมจของ Docker เราไม่ได้เปลี่ยนการตั้งค่าเริ่มต้นสำหรับประเภทโวลุ่ม EBS ของ gp3 เนื่องจากไม่เหมาะกับกรณีของเรา unpigz Hotfix สำหรับการกู้คืนคลัสเตอร์ ในขั้นตอนแรกเราตัดสินใจที่จะลดจำนวน POD บนโหนด เราย้ายโหนดใหม่ไปยังสถานะ “Cordon” ถอด PODS ที่ติดอยู่ทั้งหมดออกเพื่อลดแรงกดของดิสก์ รัน POD ทีละตัวเพื่ออุ่นเครื่องโหนด หลังจากนั้นเราจะย้ายโหนดที่อุ่นเครื่องแล้วไปสู่สถานะปกติ (“unCordon”) ลบโหนดทั้งหมดในสถานะค้างอยู่ PODS ทั้งหมดเริ่มทำงานได้สำเร็จโดยใช้แคชภาพ Docker การออกแบบ CI/CD ดั้งเดิม แนวคิดหลักของโซลูชันนี้คือการวอร์มอัปโหนดก่อนที่กระบวนการ CD จะเริ่มต้นโดยใช้ส่วนที่ใหญ่ที่สุดของอิมเมจ Docker (เลเยอร์การพึ่งพา JS) ซึ่งใช้เป็นอิมเมจรูทสำหรับแอปทั้งหมดของเรา เรามีอิมเมจรูทอย่างน้อย 7 ประเภทที่มีการพึ่งพา JS ซึ่งเกี่ยวข้องกับประเภทของแอป ดังนั้น มาวิเคราะห์การออกแบบ CI/CD ดั้งเดิมกัน ใน CI/CD pipeline ของเรา เรามี 3 เสาหลัก: ท่อ CI/CD ดั้งเดิม: ในขั้นตอน it: เตรียมสภาพแวดล้อม/ตัวแปร กำหนดชุดของอิมเมจที่จะสร้างใหม่ ฯลฯ... Init ในขั้นตอน : เราสร้างภาพและส่งไปยัง ECR Build ในขั้นตอน : เราจะปรับใช้รูปภาพไปยัง k8s (อัปเดตการปรับใช้ เป็นต้น...) Deploy รายละเอียดเพิ่มเติมเกี่ยวกับการออกแบบ CICD ดั้งเดิม: สาขาคุณลักษณะ (FB) ของเราแยกออกจากสาขา ในกระบวนการ CI เราจะวิเคราะห์ชุดรูปภาพที่มีการเปลี่ยนแปลงใน FB และสร้างใหม่เสมอ สาขา จะเสถียรเสมอ เนื่องจากคำจำกัดความควรมีรูปภาพพื้นฐานเวอร์ชันล่าสุดอยู่เสมอ main main เราสร้างภาพ Docker ของ JS ที่ต้องพึ่งพา (สำหรับแต่ละสภาพแวดล้อม) แยกกันและส่งไปยัง ECR เพื่อนำกลับมาใช้ใหม่เป็นภาพราก (ฐาน) ใน Dockerfile เรามีภาพ Docker ที่ต้องพึ่งพา JS ประมาณ 5–10 ประเภท FB จะถูกปรับใช้กับคลัสเตอร์ k8s ในเนมสเปซที่แยกจากกัน แต่สำหรับโหนดทั่วไปสำหรับ FB FB สามารถมีแอพได้ ~200 แอพ โดยมีขนาดภาพสูงสุด 3 GB เรามีระบบปรับขนาดคลัสเตอร์อัตโนมัติ ซึ่งปรับขนาดโหนดในคลัสเตอร์ตามโหลดหรือ PODS ที่รอดำเนินการด้วย nodeSelector และค่าความคลาดเคลื่อนที่สอดคล้องกัน เราใช้จุดอินสแตนซ์สำหรับโหนด การดำเนินการตามกระบวนการวอร์มอัพ มีข้อกำหนดสำหรับกระบวนการอุ่นเครื่อง บังคับ: : จัดการและแก้ไขปัญหา การแก้ไขปัญหา ContainerCreating : ลดเวลาในการเริ่มต้นระบบอย่างมากด้วยการใช้อิมเมจฐานที่อุ่นไว้ล่วงหน้า (การอ้างอิง JS) ปรับปรุงประสิทธิภาพ ดีใจที่มีการปรับปรุง: : ช่วยให้สามารถเปลี่ยนแปลงประเภทโหนดและอายุการใช้งานได้อย่างง่ายดาย (เช่น SLA ที่สูงหรือระยะเวลาการใช้งานที่ขยายออกไป) ความยืดหยุ่น : ให้มาตรวัดที่ชัดเจนเกี่ยวกับการใช้งานและประสิทธิภาพ ความโปร่งใส : ประหยัดต้นทุนด้วยการลบ VNG ทันทีหลังจากลบสาขาฟีเจอร์ที่เกี่ยวข้อง ประสิทธิภาพด้านต้นทุน : แนวทางนี้ทำให้แน่ใจว่าสภาพแวดล้อมอื่น ๆ จะไม่ได้รับผลกระทบ การแยกตัว สารละลาย หลังจากวิเคราะห์ข้อกำหนดและข้อจำกัดแล้ว เราตัดสินใจที่จะใช้กระบวนการวอร์มอัพที่จะอุ่นโหนดด้วยอิมเมจแคช JS พื้นฐาน กระบวนการนี้จะถูกเรียกใช้ก่อนที่กระบวนการ CD จะเริ่มต้น เพื่อให้แน่ใจว่าโหนดพร้อมสำหรับการใช้งาน FB และเรามีโอกาสสูงสุดที่จะเข้าถึงแคช การปรับปรุงนี้เราแบ่งออกเป็นขั้นตอนใหญ่ๆ ดังนี้: สร้าง (Virtual Node Group) ชุดโหนด ต่อแต่ละ FB เพิ่ม สำหรับโหนดใหม่ รูปภาพพื้นฐานลงในสคริปต์ cloud-init เพิ่ม พร้อมกับส่วน เพื่อดาวน์โหลดภาพ Docker ที่จำเป็นไปยังโหนดก่อนที่กระบวนการ CD จะเริ่มต้น ขั้นตอนก่อนการปรับใช้เพื่อรัน DaemonSet initContainers CI/CD Pipeline ที่อัปเดตจะมีลักษณะดังนี้: CI/CD Pipeline ที่อัปเดต: ขั้นตอน 1.1.(ขั้นตอนใหม่) : หากเป็นการเริ่มต้น FB ครั้งแรก ให้สร้างชุดส่วนบุคคลใหม่ของอินสแตนซ์โหนด (ในเงื่อนไขของเราคือ Virtual Node Group หรือ VNG) และดาวน์โหลดอิมเมจพื้นฐานของ JS ทั้งหมด (5–10 อิมเมจ) จากสาขาหลัก การดำเนินการนี้ถือว่ายุติธรรม เพราะเราได้แยก FB ออกจากสาขาหลัก จุดสำคัญคือ นี่ไม่ใช่การดำเนินการบล็อก การเริ่มต้น การเริ่มใช้งาน ขั้นตอน การสร้าง ขั้น ดาวน์โหลดอิมเมจฐาน JS ที่สดใหม่พร้อมแท็ก FB เฉพาะจาก ECR 3.1.(ขั้นตอนใหม่) : เป็นการดำเนินการบล็อค เนื่องจากเราควรลดแรงกดดันของดิสก์ ทีละรายการ เราจะดาวน์โหลดอิมเมจพื้นฐานสำหรับแต่ละโหนดที่เกี่ยวข้อง อย่างไรก็ตาม ขอขอบคุณสำหรับขั้นตอน “ เรามีภาพ Docker พื้นฐานจากสาขาหลักแล้ว ซึ่งทำให้มีโอกาสสูงที่จะเข้าถึงแคชในการเริ่มต้นครั้งแรก ตอนก่อนการปรับใช้ จุดสำคัญ การปรับใช้ init” **การใช้งาน **ไม่มีการเปลี่ยนแปลงในขั้นตอนนี้ แต่ด้วยขั้นตอนก่อนหน้านี้ เรามีเลเยอร์ภาพ Docker ขนาดใหญ่ทั้งหมดบนโหนดที่จำเป็นแล้ว ขั้นตอนการใช้งาน Init ผ่านการเรียก API (ไปยังระบบปรับขนาดอัตโนมัติของบุคคลที่สาม) จากไปป์ไลน์ CI ของเรา สร้างชุดโหนดใหม่สำหรับแต่ละ FB ปัญหาที่ได้รับการแก้ไข: : FB แต่ละอันมีชุดโหนดของตัวเอง เพื่อให้แน่ใจว่าสภาพแวดล้อมจะไม่ได้รับผลกระทบจาก FB อื่นๆ การแยก : เราสามารถเปลี่ยนประเภทโหนดและอายุการใช้งานได้อย่างง่ายดาย ความยืดหยุ่น : เราสามารถลบโหนดได้ทันทีหลังจากลบ FB ประสิทธิภาพด้านต้นทุน : เราสามารถติดตามการใช้งานและประสิทธิภาพของโหนดได้อย่างง่ายดาย (แต่ละโหนดมีแท็กที่เกี่ยวข้องกับ FB) ความโปร่งใส : Spot Instance เริ่มต้นด้วยอิมเมจพื้นฐานที่กำหนดไว้แล้ว ซึ่งหมายความว่า หลังจากที่โหนด Spot เริ่มทำงาน ก็มีอิมเมจพื้นฐานอยู่บนโหนดแล้ว (จากสาขาหลัก) การใช้งาน Spot Instance อย่างมีประสิทธิผล ผ่านสคริปต์ ดาวน์โหลดภาพฐาน JS ทั้งหมดจากสาขาหลักไปยังโหนดใหม่ cloud-init ในขณะที่กำลังดาวน์โหลดรูปภาพในพื้นหลัง กระบวนการ CD สามารถสร้างรูปภาพใหม่ต่อไปได้โดยไม่มีปัญหาใดๆ นอกจากนี้ โหนดถัดไป (ซึ่งจะสร้างขึ้นโดยระบบปรับขนาดอัตโนมัติ) จากกลุ่มนี้จะถูกสร้างขึ้นโดยใช้ข้อมูล ที่อัปเดตแล้ว ซึ่งมีคำแนะนำในการดาวน์โหลดรูปภาพก่อนเริ่มต้นอยู่แล้ว cloud-init ปัญหาที่ได้รับการแก้ไข: : แรงกดดันของดิสก์หายไปแล้ว เนื่องจากเราอัปเดตสคริปต์ โดยเพิ่มการดาวน์โหลดอิมเมจฐานจากสาขาหลัก วิธีนี้ช่วยให้เราเข้าถึงแคชได้เมื่อเริ่มต้น FB ครั้งแรก การแก้ไขปัญหา cloud-init : อินสแตนซ์จุดจะเริ่มต้นด้วยข้อมูลการเริ่มต้น ที่อัปเดต ซึ่งหมายความว่า หลังจากโหนดจุดเริ่มทำงานแล้ว จะมีอิมเมจพื้นฐานบนโหนด (จากสาขาหลัก) อยู่แล้ว การใช้งานอินสแตนซ์จุดอย่างมีประสิทธิภาพ cloud-init : กระบวนการ CD สามารถสร้างภาพใหม่ต่อไปได้โดยไม่มีปัญหาใดๆ ประสิทธิภาพการทำงานที่ได้รับการปรับปรุง การดำเนินการนี้เพิ่มเวลา ~17 วินาที (การเรียก API) ให้กับไปป์ไลน์ CI/CD ของเรา การดำเนินการนี้จะสมเหตุสมผลเฉพาะในครั้งแรกที่เราเริ่ม FB เท่านั้น ในครั้งถัดไป เราจะปรับใช้แอปของเรากับโหนดที่มีอยู่แล้ว ซึ่งมีอิมเมจพื้นฐานที่เราได้ส่งมอบไปแล้วในการปรับใช้ครั้งก่อน ขั้นตอนก่อนการใช้งาน เราจำเป็นต้องทำขั้นตอนนี้เนื่องจากรูปภาพ FB แตกต่างจากรูปภาพสาขาหลัก เราจำเป็นต้องดาวน์โหลดรูปภาพฐาน FB ไปยังโหนดก่อนที่กระบวนการ CD จะเริ่มต้น ซึ่งจะช่วยลดเวลาในการเริ่มต้นระบบแบบเย็นที่ยาวนานและการใช้ดิสก์สูงที่อาจเกิดขึ้นได้เมื่อดึงรูปภาพขนาดใหญ่หลายภาพพร้อมกัน วัตถุประสงค์ของขั้นตอนก่อนการปรับใช้ : ดาวน์โหลดรูปภาพขนาดใหญ่ที่สุดของ Docker ตามลำดับ หลังจากขั้นตอน init-deploy แล้ว เราก็มีรูปภาพพื้นฐานบนโหนดแล้ว ซึ่งหมายความว่าเรามีโอกาสสูงที่จะเกิดแคชที่ได้รับผลกระทบ ป้องกันแรงกดดันของดิสก์ : ช่วยให้แน่ใจว่าโหนดได้รับการอุ่นเครื่องล่วงหน้าด้วยอิมเมจ Docker ที่จำเป็น ซึ่งจะนำไปสู่เวลาในการเริ่มต้น POD ที่เร็วขึ้น (เกือบจะทันที) ปรับปรุงประสิทธิภาพการใช้งาน : ลดโอกาสที่จะพบข้อผิดพลาด / และตรวจสอบให้แน่ใจว่าชุดเดมอนของระบบยังคงอยู่ในสถานะ "พร้อม" เพิ่มเสถียรภาพ ErrImagePull ContainerCreating ในขั้นตอนนี้ เราจะเพิ่มเวลาให้กับกระบวนการซีดี 10–15 นาที รายละเอียดขั้นตอนก่อนการใช้งาน: ในซีดี เราสร้าง DaemonSet ด้วยส่วน initContainers ส่วน จะถูกดำเนินการก่อนที่คอนเทนเนอร์หลักจะเริ่มต้น เพื่อให้แน่ใจว่ามีการดาวน์โหลดรูปภาพที่จำเป็นก่อนที่คอนเทนเนอร์หลักจะเริ่มต้น initContainers ในซีดี เราจะตรวจสอบสถานะของ daemonSet อย่างต่อเนื่อง หาก daemonSet อยู่ในสถานะ "พร้อม" เราจะดำเนินการปรับใช้ มิฉะนั้น เราจะรอให้ daemonSet พร้อม การเปรียบเทียบ การเปรียบเทียบขั้นตอนเดิมและขั้นตอนที่อัปเดตกับกระบวนการอุ่นล่วงหน้า ขั้นตอน ขั้นตอนการใช้งาน Init ขั้นตอนก่อนการใช้งาน การใช้งาน เวลารวม ต่าง โดยไม่ต้องอุ่นเครื่อง 0 0 11นาที 21วินาที 11นาที 21วินาที 0 ด้วยการอุ่นเครื่องล่วงหน้า 8 วินาที 58 วินาที 25 วินาที 1นาที 31วินาที -9นาที50วินาที สิ่งสำคัญคือเวลา "Deploy" เปลี่ยนไป (จากคำสั่ง Apply แรกไปจนถึงสถานะ Running ของพ็อด) จาก 11 นาที 21 วินาที เป็น 25 วินาที เวลารวมเปลี่ยนจาก 11 นาที 21 วินาที เป็น 1 นาที 31 วินาที ประเด็นสำคัญคือ หากไม่มีอิมเมจฐานจากสาขาหลัก เวลา "ปรับใช้" จะเท่ากับเวลาเดิมหรืออาจมากกว่าเล็กน้อย แต่ถึงอย่างไร เราก็ได้แก้ไขปัญหาความดันดิสก์และเวลาเริ่มต้นระบบแบบเย็นแล้ว บทสรุป ปัญหาหลัก ได้รับการแก้ไขด้วยกระบวนการวอร์มอัพ ผลที่ได้คือ เราลดเวลาการเริ่มระบบแบบเย็นของ POD ได้อย่างมาก แรงกดดันของดิสก์หายไปแล้ว เนื่องจากเรามีอิมเมจพื้นฐานบนโหนดแล้ว daemonSet ของระบบอยู่ในสถานะ "พร้อม" และ "มีสุขภาพดี" (เนื่องจากไม่มีแรงกดดันของดิสก์) และเราไม่พบข้อผิดพลาด ใดๆ ที่เกี่ยวข้องกับปัญหานี้ ContainerCreating ErrImagePull วิธีแก้ปัญหาและลิงค์ที่เป็นไปได้ ใช้อินสแตนซ์ สำหรับโหนดแทนอิน เราไม่สามารถใช้วิธีนี้ได้ เนื่องจากเกินขอบเขตงบประมาณสำหรับสภาพแวดล้อมที่ไม่เกี่ยวข้องกับการผลิต ตามความต้องการ สแตนซ์จุด เราไม่สามารถใช้วิธีนี้ได้ เนื่องจากฟีเจอร์นี้ยังเกินขอบเขตงบประมาณสำหรับสภาพแวดล้อมที่ไม่ใช่การผลิตอีกด้วย นอกจากนี้ AWS ยังมี ของ IOPS สำหรับบัญชีของคุณในแต่ละภูมิภาคอีกด้วย ใช้ประเภทไดรฟ์ข้อมูล Amazon EBS gp3 (หรือดีกว่า) พร้อม IOPS ที่เพิ่มขึ้น ข้อจำกัด จริงๆ แล้วเราไม่สามารถเคลื่อนตัวในลักษณะนี้ได้ เพราะมันมีผลกระทบต่อการผลิตและสภาพแวดล้อมอื่นๆ มากเกินไป แต่นี่ก็เป็นวิธีแก้ปัญหาที่ดีเช่นกัน ลดเวลาเริ่มต้นคอนเทนเนอร์บน Amazon EKS ด้วยปริมาณข้อมูลของ Bottlerocket การแก้ไขปัญหา Kubernetes Cluster Autoscaler ใช้เวลา 1 ชั่วโมงในการปรับขนาดพ็อด 600 พ็อดขึ้น ฉันอยากจะแสดงความชื่นชมต่อทีมงานด้านเทคนิคที่ยอดเยี่ยมของ ( ) สำหรับการทำงานอย่างไม่รู้จักเหน็ดเหนื่อยและแนวทางที่สร้างสรรค์อย่างแท้จริงในการแก้ไขปัญหาต่างๆ ที่พวกเขาเผชิญ โดยเฉพาะอย่างยิ่ง ขอแสดงความชื่นชมต่อ Ronny Sharaby หัวหน้าที่ยอดเยี่ยมซึ่งรับผิดชอบต่องานอันยอดเยี่ยมที่ทีมงานกำลังทำอยู่ ฉันตั้งตารอที่จะเห็นตัวอย่างที่ยอดเยี่ยมมากขึ้นเรื่อยๆ ว่าความคิดสร้างสรรค์ของคุณส่งผลต่อผลิตภัณฑ์ของ Justt อย่างไร ป.ล.: Justt https://www.linkedin.com/company/justt-ai