บทความนี้กล่าวถึงปัญหาการทำความสะอาดอิมเมจที่สะสมอยู่ในรีจิสทรีคอนเทนเนอร์ (Docker Registry และแอนะล็อก) ในความเป็นจริงของไปป์ไลน์ CI/CD สมัยใหม่สำหรับแอปพลิเคชันเนทิฟบนคลาวด์ที่ส่งไปยัง Kubernetes เกณฑ์หลักสำหรับความเกี่ยวข้องของรูปภาพและปัญหาที่เกิดขึ้นในการทำความสะอาดอัตโนมัติ ประหยัดพื้นที่ และตอบสนองความต้องการของทีม สุดท้ายนี้ เราจะบอกคุณว่าจะสามารถเอาชนะความยากลำบากเหล่านี้ได้อย่างไรโดยใช้ตัวอย่างของโครงการโอเพ่นซอร์สที่เฉพาะเจาะจง
การแนะนำ
จำนวนอิมเมจในคอนเทนเนอร์รีจีสทรีอาจเพิ่มขึ้นอย่างรวดเร็ว ใช้พื้นที่จัดเก็บมากขึ้น และทำให้ต้นทุนเพิ่มขึ้นอย่างมาก เพื่อควบคุม จำกัด หรือรักษาการเติบโตของพื้นที่ที่ยอมรับได้ในรีจิสทรี จะต้องยอมรับ:
- ใช้แท็กจำนวนคงที่สำหรับรูปภาพ
- ทำความสะอาดภาพในทางใดทางหนึ่ง
ข้อจำกัดแรกบางครั้งอาจยอมรับได้สำหรับทีมขนาดเล็ก หากนักพัฒนาซอฟต์แวร์มีแท็กถาวรเพียงพอ (latest
, main
, test
, boris
ฯลฯ ) รีจิสทรีจะไม่ขยายขนาดและคุณไม่ต้องคิดเรื่องการทำความสะอาดเลยเป็นเวลานาน ท้ายที่สุดแล้ว รูปภาพที่ไม่เกี่ยวข้องทั้งหมดจะถูกลบ และไม่มีงานเหลือสำหรับการทำความสะอาด (ทุกอย่างทำโดยคนเก็บขยะทั่วไป)
อย่างไรก็ตาม วิธีการนี้จำกัดการพัฒนาอย่างมาก และไม่ค่อยนำไปใช้กับโครงการ CI/CD สมัยใหม่ ส่วนสำคัญของการพัฒนาก็คือ อัตโนมัติซึ่งช่วยให้คุณทดสอบ ปรับใช้ และส่งมอบฟังก์ชันการทำงานใหม่ๆ ให้กับผู้ใช้ได้รวดเร็วยิ่งขึ้น ตัวอย่างเช่น ในทุกโปรเจ็กต์ของเรา ไปป์ไลน์ CI จะถูกสร้างขึ้นโดยอัตโนมัติพร้อมกับคอมมิตแต่ละรายการ ในนั้น รูปภาพจะถูกประกอบ ทดสอบ และเผยแพร่ไปยังวงจร Kubernetes ต่างๆ เพื่อการดีบักและการตรวจสอบที่เหลือ และหากทุกอย่างเรียบร้อยดี การเปลี่ยนแปลงจะไปถึงผู้ใช้ปลายทาง และนี่ไม่ใช่วิทยาศาสตร์จรวดอีกต่อไป แต่เกิดขึ้นทุกวันสำหรับหลายๆ คน ซึ่งน่าจะเป็นไปได้มากที่สุดสำหรับคุณ เนื่องจากคุณกำลังอ่านบทความนี้
เนื่องจากการแก้ไขจุดบกพร่องและการพัฒนาฟังก์ชันใหม่ ๆ จะดำเนินการไปพร้อม ๆ กัน และสามารถเผยแพร่ได้หลายครั้งต่อวัน เห็นได้ชัดว่ากระบวนการพัฒนามาพร้อมกับข้อผูกพันจำนวนมาก ซึ่งหมายถึง รูปภาพจำนวนมากในรีจิสตรี. เป็นผลให้เกิดปัญหาในการจัดการทำความสะอาดรีจิสทรีอย่างมีประสิทธิภาพเช่น การลบรูปภาพที่ไม่เกี่ยวข้องออก
แต่คุณจะทราบได้อย่างไรว่ารูปภาพนั้นมีความเกี่ยวข้องหรือไม่
เกณฑ์สำหรับความเกี่ยวข้องของภาพ
ในกรณีส่วนใหญ่ เกณฑ์หลักจะเป็นดังนี้:
1. ภาพแรก (ที่ชัดเจนที่สุดและสำคัญที่สุด) คือภาพนั้น ที่ใช้ใน Kubernetes ในปัจจุบัน. การลบอิมเมจเหล่านี้ออกอาจส่งผลให้เกิดต้นทุนการหยุดทำงานของการผลิตอย่างมีนัยสำคัญ (เช่น รูปภาพอาจจำเป็นสำหรับการจำลอง) หรือลบล้างความพยายามของทีมในการแก้ไขข้อบกพร่องในลูปใดๆ (ด้วยเหตุนี้เราจึงได้จัดทำรายการพิเศษขึ้นมาด้วย
2. ประการที่สอง (ไม่ชัดเจนแต่มีความสำคัญมากและเกี่ยวข้องกับการแสวงหาผลประโยชน์อีกครั้ง) - รูปภาพนั้น จำเป็นสำหรับการย้อนกลับในกรณีที่ตรวจพบปัญหาร้ายแรง ในเวอร์ชันปัจจุบัน ตัวอย่างเช่น ในกรณีของ Helm รูปภาพเหล่านี้คือรูปภาพที่ใช้ในเวอร์ชันที่บันทึกไว้ของการเผยแพร่ (อย่างไรก็ตาม ตามค่าเริ่มต้นใน Helm ขีดจำกัดอยู่ที่ 256 การแก้ไข แต่ก็ไม่น่าจะมีใครต้องการบันทึกจริงๆ เช่น เป็นจำนวนมาก?..) โดยเฉพาะอย่างยิ่งเราเก็บเวอร์ชันต่างๆ ไว้ เพื่อที่เราจะได้ใช้ในภายหลัง กล่าวคือ “ย้อนกลับ” ให้พวกเขาหากจำเป็น
3. สาม - ความต้องการของนักพัฒนา: รูปภาพทั้งหมดที่เกี่ยวข้องกับงานปัจจุบันของพวกเขา ตัวอย่างเช่น หากเรากำลังพิจารณา PR ก็สมเหตุสมผลที่จะทิ้งรูปภาพที่สอดคล้องกับการคอมมิตครั้งล่าสุดและเช่นการคอมมิตก่อนหน้า: ด้วยวิธีนี้นักพัฒนาสามารถกลับไปที่งานใด ๆ ได้อย่างรวดเร็วและทำงานกับการเปลี่ยนแปลงล่าสุด
4. ประการที่สี่ - รูปภาพนั้น สอดคล้องกับเวอร์ชันของแอปพลิเคชันของเรา, เช่น. เป็นผลิตภัณฑ์ขั้นสุดท้าย: v1.0.0, 20.04.01/XNUMX/XNUMX, เซียร่า ฯลฯ
หมายเหตุ: เกณฑ์ที่กำหนดไว้ในที่นี้จัดทำขึ้นจากประสบการณ์ในการโต้ตอบกับทีมพัฒนาหลายสิบทีมจากบริษัทต่างๆ อย่างไรก็ตาม แน่นอนว่า ขึ้นอยู่กับข้อมูลเฉพาะในกระบวนการพัฒนาและโครงสร้างพื้นฐานที่ใช้ (เช่น ไม่ได้ใช้ Kubernetes) เกณฑ์เหล่านี้อาจแตกต่างกัน
คุณสมบัติและโซลูชั่นที่มีอยู่
ตามกฎแล้วบริการยอดนิยมที่มีการลงทะเบียนคอนเทนเนอร์จะเสนอนโยบายการล้างรูปภาพของตนเอง: ในนั้นคุณสามารถกำหนดเงื่อนไขในการลบแท็กออกจากรีจิสทรีได้ อย่างไรก็ตาม เงื่อนไขเหล่านี้ถูกจำกัดด้วยพารามิเตอร์ เช่น ชื่อ เวลาในการสร้าง และจำนวนแท็ก*
* ขึ้นอยู่กับการใช้งานรีจิสตรีคอนเทนเนอร์เฉพาะ เราพิจารณาความเป็นไปได้ของโซลูชันต่อไปนี้: Azure CR, Docker Hub, ECR, GCR, แพ็คเกจ GitHub, GitLab Container Registry, Harbor Registry, JFrog Artifactory, Quay.io - ณ เดือนกันยายน 2020
ชุดพารามิเตอร์นี้เพียงพอที่จะตอบสนองเกณฑ์ที่สี่ - นั่นคือเพื่อเลือกรูปภาพที่สอดคล้องกับเวอร์ชัน อย่างไรก็ตาม สำหรับเกณฑ์อื่นๆ ทั้งหมด เราจะต้องเลือกวิธีการประนีประนอมบางประเภท (นโยบายที่เข้มงวดกว่าหรือในทางกลับกัน คือผ่อนปรนมากกว่า) ขึ้นอยู่กับความคาดหวังและความสามารถทางการเงิน
ตัวอย่างเช่น เกณฑ์ที่สามที่เกี่ยวข้องกับความต้องการของนักพัฒนา สามารถแก้ไขได้โดยการจัดระเบียบกระบวนการภายในทีม: การตั้งชื่อรูปภาพเฉพาะ การรักษารายการอนุญาตพิเศษ และข้อตกลงภายใน แต่ท้ายที่สุดแล้ว มันยังต้องเป็นไปโดยอัตโนมัติ และหากความสามารถของโซลูชันสำเร็จรูปยังไม่เพียงพอ คุณต้องทำอะไรด้วยตนเอง
สถานการณ์ที่มีเกณฑ์สองข้อแรกนั้นคล้ายคลึงกัน: ไม่สามารถพอใจได้หากไม่ได้รับข้อมูลจากระบบภายนอก - ซึ่งเป็นที่ที่มีการปรับใช้แอปพลิเคชัน (ในกรณีของเราคือ Kubernetes)
ภาพประกอบของเวิร์กโฟลว์ใน Git
สมมติว่าคุณกำลังทำงานแบบนี้ใน Git:
ไอคอนที่มีส่วนหัวในไดอะแกรมบ่งบอกถึงอิมเมจคอนเทนเนอร์ที่ใช้งานอยู่ใน Kubernetes สำหรับผู้ใช้ทุกคน (ผู้ใช้ปลายทาง ผู้ทดสอบ ผู้จัดการ ฯลฯ) หรือที่นักพัฒนาซอฟต์แวร์ใช้เพื่อการแก้ไขจุดบกพร่องและวัตถุประสงค์ที่คล้ายกัน
จะเกิดอะไรขึ้นหากนโยบายการล้างข้อมูลอนุญาตให้เก็บเฉพาะรูปภาพเท่านั้น (ไม่ถูกลบ) โดยระบุชื่อแท็ก?
แน่นอนว่าสถานการณ์เช่นนี้จะไม่ทำให้ใครมีความสุข
จะเกิดอะไรขึ้นหากนโยบายไม่อนุญาตให้ลบรูปภาพ ตามช่วงเวลาที่กำหนด / จำนวนการคอมมิตครั้งล่าสุด?
ผลลัพธ์ดีขึ้นมาก แต่ก็ยังห่างไกลจากอุดมคติ ท้ายที่สุดแล้ว เรายังมีนักพัฒนาที่ต้องการอิมเมจในรีจิสทรี (หรือแม้แต่ปรับใช้ใน K8) เพื่อแก้ไขจุดบกพร่อง...
เพื่อสรุปสถานการณ์ตลาดในปัจจุบัน: ฟังก์ชันที่มีอยู่ในการลงทะเบียนคอนเทนเนอร์ไม่มีความยืดหยุ่นเพียงพอในการทำความสะอาด และเหตุผลหลักก็คือ ไม่มีทางที่จะโต้ตอบกับโลกภายนอกได้. ปรากฎว่าทีมที่ต้องการความยืดหยุ่นดังกล่าวถูกบังคับให้ดำเนินการลบรูปภาพ "จากภายนอก" อย่างอิสระโดยใช้ Docker Registry API (หรือ API ดั้งเดิมของการใช้งานที่เกี่ยวข้อง)
อย่างไรก็ตาม เรากำลังมองหาโซลูชันสากลที่จะทำการล้างข้อมูลรูปภาพโดยอัตโนมัติสำหรับทีมต่างๆ โดยใช้รีจิสทรีที่แตกต่างกัน...
เส้นทางสู่การทำความสะอาดภาพแบบสากลของเรา
ความต้องการนี้มาจากไหน? ความจริงก็คือเราไม่ใช่กลุ่มนักพัฒนาที่แยกจากกัน แต่เป็นทีมที่ทำหน้าที่นักพัฒนาหลายคนในคราวเดียว ซึ่งช่วยแก้ไขปัญหา CI/CD อย่างครอบคลุม และเครื่องมือทางเทคนิคหลักสำหรับสิ่งนี้คือยูทิลิตี้ Open Source
การเผยแพร่รูปภาพไปยังรีจิสทรี* (ทันทีหลังจากสร้างขึ้น) เป็นฟังก์ชันที่ชัดเจนของยูทิลิตี้ดังกล่าว และเนื่องจากรูปภาพถูกวางไว้ที่นั่นเพื่อจัดเก็บ ดังนั้น หากพื้นที่เก็บข้อมูลของคุณไม่จำกัด คุณจะต้องรับผิดชอบในการทำความสะอาดในภายหลัง เราจะหารือเพิ่มเติมเกี่ยวกับวิธีที่เราประสบความสำเร็จในเรื่องนี้และเป็นไปตามเกณฑ์ที่ระบุทั้งหมด
* แม้ว่ารีจิสทรีอาจแตกต่างกัน (Docker Registry, GitLab Container Registry, Harbor ฯลฯ) ผู้ใช้ก็ประสบปัญหาเดียวกัน โซลูชันสากลในกรณีของเราไม่ได้ขึ้นอยู่กับการใช้งานรีจิสทรีเพราะ ทำงานนอกรีจิสทรีและเสนอพฤติกรรมแบบเดียวกันสำหรับทุกคน
แม้ว่าเราจะใช้ werf เป็นตัวอย่างในการใช้งาน แต่เราหวังว่าแนวทางที่ใช้จะเป็นประโยชน์กับทีมอื่น ๆ ที่เผชิญกับปัญหาที่คล้ายกัน
ดังนั้นเราจึงยุ่ง ภายนอก การใช้กลไกในการทำความสะอาดอิมเมจ - แทนความสามารถที่มีอยู่แล้วในการลงทะเบียนสำหรับคอนเทนเนอร์ ขั้นตอนแรกคือการใช้ Docker Registry API เพื่อสร้างนโยบายดั้งเดิมที่เหมือนกันสำหรับจำนวนแท็กและเวลาที่สร้าง (ดังที่กล่าวไว้ข้างต้น) เพิ่มให้กับพวกเขา รายการที่อนุญาตตามรูปภาพที่ใช้ในโครงสร้างพื้นฐานที่ปรับใช้, เช่น. คูเบอร์เนเตส ประการหลัง การใช้ Kubernetes API เพื่อวนซ้ำทรัพยากรที่ปรับใช้ทั้งหมดและรับรายการค่าก็เพียงพอแล้ว image
.
วิธีแก้ปัญหาเล็กๆ น้อยๆ นี้ช่วยแก้ปัญหาที่สำคัญที่สุดได้ (เกณฑ์ข้อ 1) แต่เป็นเพียงจุดเริ่มต้นของการเดินทางของเราเพื่อปรับปรุงกลไกการทำความสะอาด ขั้นตอนถัดไปและน่าสนใจกว่ามากคือการตัดสินใจ เชื่อมโยงภาพที่เผยแพร่กับประวัติ Git.
รูปแบบการแท็ก
ขั้นแรก เราเลือกวิธีการที่รูปภาพสุดท้ายควรจัดเก็บข้อมูลที่จำเป็นสำหรับการทำความสะอาด และสร้างกระบวนการในการแท็กแผนการ เมื่อเผยแพร่รูปภาพ ผู้ใช้เลือกตัวเลือกการแท็กเฉพาะ (git-branch
, git-commit
หรือ git-tag
) และใช้ค่าที่สอดคล้องกัน ในระบบ CI ค่าเหล่านี้จะถูกตั้งค่าโดยอัตโนมัติตามตัวแปรสภาพแวดล้อม ในความเป็นจริง ภาพสุดท้ายเชื่อมโยงกับ Git ดั้งเดิมเฉพาะจัดเก็บข้อมูลที่จำเป็นสำหรับการทำความสะอาดไว้ในฉลาก
แนวทางนี้ส่งผลให้มีชุดนโยบายที่อนุญาตให้ใช้ Git เป็นแหล่งความจริงแหล่งเดียว:
- เมื่อลบสาขา/แท็กใน Git รูปภาพที่เกี่ยวข้องในรีจิสทรีจะถูกลบโดยอัตโนมัติ
- จำนวนรูปภาพที่เกี่ยวข้องกับแท็ก Git และคอมมิตสามารถควบคุมได้โดยจำนวนแท็กที่ใช้ในสคีมาที่เลือกและเวลาที่สร้างคอมมิตที่เกี่ยวข้อง
โดยรวมแล้ว ผลลัพธ์ของการนำไปปฏิบัตินั้นสนองความต้องการของเรา แต่ในไม่ช้า ความท้าทายใหม่ก็รอเราอยู่ ความจริงก็คือในขณะที่ใช้รูปแบบการแท็กตาม Git ดั้งเดิม เราพบข้อบกพร่องหลายประการ (เนื่องจากคำอธิบายอยู่นอกเหนือขอบเขตของบทความนี้ ทุกคนจึงสามารถทำความคุ้นเคยกับรายละเอียดได้
อัลกอริธึมใหม่
ทำไม ด้วยการแท็กตามเนื้อหา แต่ละแท็กสามารถตอบสนองคอมมิตหลายรายการใน Git เมื่อทำความสะอาดภาพ คุณจะไม่สามารถคาดเดาได้อีกต่อไป เท่านั้น จากการกระทำที่มีการเพิ่มแท็กใหม่ลงในรีจิสทรี
สำหรับอัลกอริธึมการทำความสะอาดใหม่ มีการตัดสินใจที่จะย้ายออกจากรูปแบบการแท็กและการสร้าง กระบวนการเมตาอิมเมจซึ่งแต่ละแห่งจะเก็บกลุ่มของ:
- การกระทำที่ดำเนินการเผยแพร่ (ไม่สำคัญว่ารูปภาพจะถูกเพิ่ม เปลี่ยนแปลง หรือคงเหมือนเดิมในรีจิสตรีคอนเทนเนอร์)
- และตัวระบุภายในของเราที่สอดคล้องกับภาพที่ประกอบ
กล่าวอีกนัยหนึ่งก็มีให้ การเชื่อมโยงแท็กที่เผยแพร่กับการคอมมิตใน Git.
การกำหนดค่าขั้นสุดท้ายและอัลกอริธึมทั่วไป
เมื่อกำหนดค่าการทำความสะอาด ผู้ใช้จะสามารถเข้าถึงนโยบายที่เลือกรูปภาพปัจจุบันได้ แต่ละนโยบายดังกล่าวถูกกำหนดไว้:
- มีการอ้างอิงมากมาย เช่น แท็ก Git หรือสาขา Git ที่ใช้ระหว่างการสแกน
- และขีดจำกัดการค้นหารูปภาพสำหรับการอ้างอิงแต่ละรายการจากชุด
เพื่อแสดงให้เห็น นี่คือลักษณะที่การกำหนดค่านโยบายเริ่มต้นเริ่มมีลักษณะดังนี้:
cleanup:
keepPolicies:
- references:
tag: /.*/
limit:
last: 10
- references:
branch: /.*/
limit:
last: 10
in: 168h
operator: And
imagesPerReference:
last: 2
in: 168h
operator: And
- references:
branch: /^(main|staging|production)$/
imagesPerReference:
last: 10
การกำหนดค่านี้มีนโยบาย XNUMX รายการที่สอดคล้องกับกฎต่อไปนี้:
- บันทึกรูปภาพสำหรับแท็ก Git 10 รายการล่าสุด (ตามวันที่สร้างแท็ก)
- บันทึกไม่เกิน 2 ภาพที่เผยแพร่ในสัปดาห์ที่ผ่านมาสำหรับไม่เกิน 10 กระทู้ที่มีกิจกรรมในสัปดาห์ที่ผ่านมา
- บันทึก 10 ภาพสำหรับสาขา
main
,staging
иproduction
.
อัลกอริธึมสุดท้ายจะมีขั้นตอนต่อไปนี้:
- กำลังดึงรายการจากรีจิสตรีคอนเทนเนอร์
- ไม่รวมรูปภาพที่ใช้ใน Kubernetes เนื่องจาก เราได้เลือกไว้ล่วงหน้าแล้วโดยการสำรวจ K8s API
- สแกนประวัติ Git และยกเว้นรูปภาพตามนโยบายที่ระบุ
- การลบภาพที่เหลือ
กลับมาที่ภาพประกอบของเรา นี่คือสิ่งที่เกิดขึ้นกับ werf:
อย่างไรก็ตาม แม้ว่าคุณจะไม่ได้ใช้ wef แต่แนวทางที่คล้ายกันในการทำความสะอาดรูปภาพขั้นสูง - ในการใช้งานอย่างใดอย่างหนึ่ง (ตามแนวทางที่ต้องการในการแท็กรูปภาพ) - สามารถนำไปใช้กับระบบ/ยูทิลิตี้อื่น ๆ ได้ ในการดำเนินการนี้ ก็เพียงพอแล้วที่จะจดจำปัญหาที่เกิดขึ้นและค้นหาโอกาสเหล่านั้นในสแต็กของคุณที่ช่วยให้คุณสามารถบูรณาการโซลูชันได้อย่างราบรื่นที่สุด เราหวังว่าเส้นทางที่เราได้เดินทางจะช่วยให้คุณพิจารณากรณีเฉพาะของคุณด้วยรายละเอียดและความคิดใหม่ ๆ
ข้อสรุป
- ไม่ช้าก็เร็ว ทีมส่วนใหญ่ประสบปัญหารีจิสทรีล้น
- เมื่อค้นหาวิธีแก้ไข ขั้นแรกจำเป็นต้องกำหนดเกณฑ์สำหรับความเกี่ยวข้องของรูปภาพ
- เครื่องมือที่นำเสนอโดยบริการรีจีสทรีคอนเทนเนอร์ยอดนิยมช่วยให้คุณสามารถจัดระเบียบการล้างข้อมูลแบบง่ายๆ ที่ไม่คำนึงถึง "โลกภายนอก": รูปภาพที่ใช้ใน Kubernetes และลักษณะเฉพาะของเวิร์กโฟลว์ของทีม
- อัลกอริธึมที่ยืดหยุ่นและมีประสิทธิภาพต้องมีความเข้าใจในกระบวนการ CI/CD และไม่เพียงดำเนินการกับข้อมูลอิมเมจ Docker เท่านั้น
PS
อ่านเพิ่มเติมในบล็อกของเรา:
- «
การแท็กตามเนื้อหาในตัวรวบรวม WRF: เหตุใดจึงทำงานอย่างไร "; - «
ผสาน 3 ทางกับ werf: การปรับใช้กับ Kubernetes ด้วย Helm “บนสเตียรอยด์” "; - «
รองรับ monorepo และ multirepo ใน werf และ Docker Registry เกี่ยวข้องกับอะไร "; - «
werf 1.1 release: การปรับปรุงตัวสร้างในวันนี้และการวางแผนสำหรับอนาคต '
ที่มา: will.com