werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

วันที่ 27 พฤษภาคม ณ ห้องโถงหลักของการประชุม DevOpsConf 2019 ซึ่งจัดขึ้นเป็นส่วนหนึ่งของเทศกาล ริท++ 2019เนื่องจากเป็นส่วนหนึ่งของส่วน "การจัดส่งอย่างต่อเนื่อง" รายงานจึงได้รับ "werf - เครื่องมือของเราสำหรับ CI/CD ใน Kubernetes" มันพูดถึงสิ่งเหล่านั้น ปัญหาและความท้าทายที่ทุกคนต้องเผชิญเมื่อปรับใช้กับ Kubernetesรวมถึงความแตกต่างที่อาจไม่สามารถสังเกตเห็นได้ในทันที การวิเคราะห์วิธีแก้ปัญหาที่เป็นไปได้ เราจะแสดงให้เห็นว่าสิ่งนี้ถูกนำไปใช้อย่างไรในเครื่องมือโอเพ่นซอร์ส เวร.

นับตั้งแต่การนำเสนอ ยูทิลิตี้ของเรา (เดิมชื่อ dapp) ได้ก้าวไปสู่เหตุการณ์สำคัญทางประวัติศาสตร์ของ 1000 ดาวบน GitHub — เราหวังว่าชุมชนผู้ใช้ที่กำลังเติบโตนี้จะทำให้ชีวิตของวิศวกร DevOps หลายคนง่ายขึ้น

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

เอาล่ะ เรามาแนะนำกันดีกว่า วิดีโอของรายงาน (ประมาณ 47 นาที มีข้อมูลมากกว่าบทความมาก) และสารสกัดหลักจากบทความนี้ในรูปแบบข้อความ ไป!

การส่งโค้ดไปยัง Kubernetes

การพูดคุยจะไม่เกี่ยวกับ werf อีกต่อไป แต่เกี่ยวกับ CI/CD ใน Kubernetes ซึ่งหมายความว่าซอฟต์แวร์ของเราได้รับการบรรจุในคอนเทนเนอร์ Docker (ผมพูดถึงเรื่องนี้ใน. รายงานประจำปี 2016)และ K8 จะถูกนำมาใช้ในการผลิต (เพิ่มเติมเกี่ยวกับเรื่องนี้ใน ปี 2017).

การจัดส่งมีลักษณะอย่างไรใน Kubernetes

  • มีพื้นที่เก็บข้อมูล Git พร้อมโค้ดและคำแนะนำในการสร้าง แอปพลิเคชันนี้สร้างไว้ในอิมเมจ Docker และเผยแพร่ใน Docker Registry
  • พื้นที่เก็บข้อมูลเดียวกันนี้ยังมีคำแนะนำเกี่ยวกับวิธีการปรับใช้และรันแอปพลิเคชันอีกด้วย ในขั้นตอนการปรับใช้ คำแนะนำเหล่านี้จะถูกส่งไปยัง Kubernetes ซึ่งรับอิมเมจที่ต้องการจากรีจิสทรีและเปิดใช้งาน
  • นอกจากนี้ก็มักจะมีการทดสอบ สิ่งเหล่านี้บางส่วนสามารถทำได้เมื่อเผยแพร่รูปภาพ คุณยังสามารถ (ทำตามคำแนะนำเดียวกัน) ปรับใช้สำเนาของแอปพลิเคชันได้ (ในเนมสเปซ K8s ที่แยกต่างหากหรือคลัสเตอร์ที่แยกต่างหาก) และทำการทดสอบที่นั่น
  • สุดท้ายนี้ คุณต้องมีระบบ CI ที่รับเหตุการณ์จาก Git (หรือการคลิกปุ่ม) และเรียกขั้นตอนที่กำหนดทั้งหมด: สร้าง เผยแพร่ ปรับใช้ ทดสอบ

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

มีหมายเหตุสำคัญบางประการที่นี่:

  1. เพราะเรามีโครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป (โครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป), อิมเมจแอปพลิเคชันที่ใช้ในทุกขั้นตอน (การจัดเตรียม, การผลิต ฯลฯ) จะต้องมีอย่างใดอย่างหนึ่ง. ฉันพูดคุยเกี่ยวกับเรื่องนี้โดยละเอียดและพร้อมตัวอย่าง ที่นี่.
  2. เพราะเราปฏิบัติตามโครงสร้างพื้นฐานเป็นแนวทางการเขียนโค้ด (ไอเอซี), รหัสแอปพลิเคชัน, คำแนะนำในการประกอบและเปิดใช้ควรจะเป็น อยู่ในที่เก็บข้อมูลเดียว. สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ โปรดดู รายงานเดียวกัน.
  3. ห่วงโซ่อุปทาน (จัดส่ง) เรามักจะเห็นแบบนี้ คือ แอปพลิเคชันถูกประกอบ ทดสอบ และเผยแพร่ (ระยะปล่อยตัว) เท่านี้ก็เรียบร้อย - มีการส่งมอบแล้ว แต่ในความเป็นจริง ผู้ใช้จะได้รับสิ่งที่คุณเปิดตัว ไม่ แล้วเมื่อคุณส่งมอบมันให้กับการผลิต และเมื่อเขาสามารถไปที่นั่นได้และการผลิตนี้ก็ได้ผล ฉันจึงเชื่อว่าห่วงโซ่การส่งมอบสิ้นสุดลง ในขั้นตอนการปฏิบัติงานเท่านั้น (วิ่ง)หรือแม่นยำยิ่งขึ้นแม้ในขณะที่รหัสถูกลบออกจากการผลิต (แทนที่ด้วยรหัสใหม่)

กลับไปที่รูปแบบการจัดส่งข้างต้นใน Kubernetes: มันไม่ได้ถูกคิดค้นโดยเราเท่านั้น แต่โดยทุกคนที่จัดการกับปัญหานี้อย่างแท้จริง จริงๆ แล้ว รูปแบบนี้เรียกว่า GitOps (คุณสามารถอ่านเพิ่มเติมเกี่ยวกับคำศัพท์และแนวคิดเบื้องหลังได้ ที่นี่). มาดูขั้นตอนของโครงการกัน

สร้างเวที

ดูเหมือนว่าคุณจะสามารถพูดคุยเกี่ยวกับการสร้างอิมเมจ Docker ได้ในปี 2019 เมื่อทุกคนรู้วิธีเขียน Dockerfiles และเรียกใช้ docker build?.. นี่คือความแตกต่างที่ฉันอยากจะใส่ใจ:

  1. น้ำหนักภาพ สำคัญดังนั้นใช้ หลายขั้นตอนเพื่อเหลือไว้ในรูปภาพเฉพาะแอปพลิเคชันที่จำเป็นจริงๆ สำหรับการดำเนินการ
  2. จำนวนชั้น จะต้องย่อให้เล็กสุดโดยการรวมโซ่ของ RUN-คำสั่งตามความหมาย
  3. อย่างไรก็ตาม สิ่งนี้จะเพิ่มปัญหา การดีบักเพราะเมื่อแอสเซมบลีล้มเหลวคุณต้องค้นหาคำสั่งที่ถูกต้องจากเชนที่ทำให้เกิดปัญหา
  4. ความเร็วในการประกอบ สำคัญเพราะเราต้องการเปิดตัวการเปลี่ยนแปลงอย่างรวดเร็วและดูผลลัพธ์ ตัวอย่างเช่น คุณไม่ต้องการสร้างการขึ้นต่อกันในไลบรารีภาษาทุกครั้งที่คุณสร้างแอปพลิเคชัน
  5. บ่อยครั้งจากพื้นที่เก็บข้อมูล Git เดียวที่คุณต้องการ หลายภาพซึ่งสามารถแก้ไขได้โดยชุดของ Dockerfiles (หรือสเตจที่มีชื่อในไฟล์เดียว) และสคริปต์ Bash พร้อมแอสเซมบลีตามลำดับ

นี่เป็นเพียงยอดภูเขาน้ำแข็งที่ทุกคนเผชิญ แต่มีปัญหาอื่น ๆ โดยเฉพาะ:

  1. บ่อยครั้งในขั้นตอนการประกอบ เราต้องการบางสิ่งบางอย่าง เมานต์ (เช่น แคชผลลัพธ์ของคำสั่ง เช่น apt ในไดเร็กทอรีบุคคลที่สาม)
  2. พวกเราต้องการ เบิ้ล แทนที่จะเขียนในเชลล์
  3. พวกเราต้องการ สร้างโดยไม่มีนักเทียบท่า (เหตุใดเราจึงต้องมีเครื่องเสมือนเพิ่มเติมซึ่งเราต้องกำหนดค่าทุกอย่างสำหรับสิ่งนี้ ในเมื่อเรามีคลัสเตอร์ Kubernetes ซึ่งเราสามารถเรียกใช้คอนเทนเนอร์ได้แล้ว)
  4. การประกอบแบบขนานซึ่งสามารถเข้าใจได้หลายวิธี: คำสั่งที่แตกต่างจาก Dockerfile (หากใช้หลายขั้นตอน), คอมมิตหลายอันจากที่เก็บเดียวกัน, Dockerfile หลายอัน
  5. การประกอบแบบกระจาย: เราอยากสะสมของในฝักที่ "ชั่วคราว" เพราะว่า แคชหายไปซึ่งหมายความว่าจำเป็นต้องจัดเก็บไว้ที่ใดที่หนึ่งแยกกัน
  6. ในที่สุดฉันก็ตั้งชื่อจุดสุดยอดของความปรารถนา มายากลอัตโนมัติ: เป็นการดีที่จะไปที่ Repository พิมพ์คำสั่งบางอย่างแล้วได้ภาพสำเร็จรูปประกอบกับความเข้าใจว่าต้องทำอย่างไรและอย่างไรให้ถูกต้อง อย่างไรก็ตามโดยส่วนตัวแล้วฉันไม่แน่ใจว่าสามารถคาดการณ์ความแตกต่างทั้งหมดได้ด้วยวิธีนี้

และนี่คือโครงการ:

  • โมบี้/บิลด์คิท — เครื่องมือสร้างจาก Docker Inc (รวมเข้ากับ Docker เวอร์ชันปัจจุบันแล้ว) ซึ่งพยายามแก้ไขปัญหาเหล่านี้ทั้งหมด
  • คานิโกะ — เครื่องมือสร้างจาก Google ที่ให้คุณสร้างโดยไม่ต้องใช้ Docker
  • Buildpacks.io — ความพยายามของ CNCF ในการสร้างเวทย์มนตร์อัตโนมัติ และโดยเฉพาะอย่างยิ่ง โซลูชั่นที่น่าสนใจพร้อมการรีเบสสำหรับเลเยอร์
  • และสาธารณูปโภคอื่นๆ อีกมากมาย เช่น บิวดาห์, เครื่องมือของแท้/img...

...และดูว่าพวกเขามีดาวกี่ดวงบน GitHub กล่าวคือ ในด้านหนึ่ง docker build มีอยู่และสามารถทำอะไรบางอย่างได้แต่ในความเป็นจริง ปัญหายังไม่ได้รับการแก้ไขอย่างสมบูรณ์ - ข้อพิสูจน์เรื่องนี้คือการพัฒนาแบบคู่ขนานของตัวสะสมทางเลือก ซึ่งแต่ละตัวสามารถแก้ปัญหาได้บางส่วน

การประกอบใน WRF

ดังนั้นเราจึงต้อง เวร (เดิม มีชื่อเสียง เหมือนแดปป์) — ยูทิลิตี้โอเพ่นซอร์สจากบริษัท Flant ซึ่งเราทำมาหลายปีแล้ว ทุกอย่างเริ่มต้นเมื่อ 5 ปีที่แล้วด้วยสคริปต์ Bash ที่ปรับการประกอบ Dockerfiles ให้เหมาะสม และในช่วง 3 ปีที่ผ่านมาการพัฒนาอย่างเต็มรูปแบบได้ดำเนินการภายใต้กรอบของโครงการเดียวที่มีพื้นที่เก็บข้อมูล Git ของตัวเอง (ครั้งแรกใน Ruby จากนั้น เขียนใหม่ to Go และในขณะเดียวกันก็เปลี่ยนชื่อ). ปัญหาการประกอบใดบ้างที่ได้รับการแก้ไขใน WERF?

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ปัญหาที่แรเงาสีน้ำเงินได้ถูกนำมาใช้แล้ว การสร้างแบบคู่ขนานเสร็จสิ้นภายในโฮสต์เดียวกัน และปัญหาที่เน้นด้วยสีเหลืองมีแผนจะแล้วเสร็จภายในสิ้นฤดูร้อน

ขั้นตอนการตีพิมพ์ในทะเบียน (เผยแพร่)

เราโทรไป docker push... - การอัพโหลดรูปภาพไปยังรีจิสตรีอาจเป็นเรื่องยากอะไร แล้วคำถามก็เกิดขึ้น: “ฉันควรใส่แท็กอะไรในภาพ?” มันเกิดขึ้นเพราะเหตุที่เรามี Gitflow (หรือกลยุทธ์ Git อื่นๆ) และ Kubernetes และอุตสาหกรรมกำลังพยายามให้แน่ใจว่าสิ่งที่เกิดขึ้นใน Kubernetes จะเป็นไปตามสิ่งที่เกิดขึ้นใน Git ท้ายที่สุดแล้ว Git เป็นแหล่งความจริงเพียงแหล่งเดียวของเรา

อะไรจะยากขนาดนี้? มั่นใจในการทำซ้ำ: จากการกระทำใน Git ซึ่งมีลักษณะไม่เปลี่ยนรูป (ไม่เปลี่ยนรูป)ไปยังอิมเมจ Docker ซึ่งควรคงไว้เหมือนเดิม

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

กลยุทธ์การแท็ก

อันแรกนั้นง่าย แท็กคอมไพล์. เรามีรีจิสทรีพร้อมรูปภาพที่แท็กเป็น 1.0. Kubernetes มีขั้นตอนและการผลิตซึ่งจะมีการอัปโหลดรูปภาพนี้ ใน Git เราทำการคอมมิตและเมื่อถึงจุดหนึ่งเราก็แท็ก 2.0. เรารวบรวมมันตามคำแนะนำจากพื้นที่เก็บข้อมูลและวางไว้ในรีจิสตรีพร้อมแท็ก 2.0. เราเปิดตัวบนเวที และหากทุกอย่างเรียบร้อยดี เราก็เข้าสู่การผลิต

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ปัญหาของแนวทางนี้คือเราใส่แท็กก่อน จากนั้นจึงทดสอบและเผยแพร่เท่านั้น ทำไม ประการแรก มันไร้เหตุผล: เรากำลังออกซอฟต์แวร์เวอร์ชันที่เรายังไม่ได้ทดสอบด้วยซ้ำ (เราทำอย่างอื่นไม่ได้ เนื่องจากในการตรวจสอบ เราต้องใส่แท็ก) ประการที่สอง เส้นทางนี้เข้ากันไม่ได้กับ Gitflow

ตัวเลือกที่สอง - คอมไพล์กระทำ + แท็ก. สาขาหลักมีแท็ก 1.0; สำหรับมันในรีจิสตรี - อิมเมจที่ปรับใช้กับการผลิต นอกจากนี้ คลัสเตอร์ Kubernetes ยังมีการแสดงตัวอย่างและการแสดงโครงร่างอีกด้วย ต่อไปเราจะติดตาม Gitflow: ในสาขาหลักเพื่อการพัฒนา (develop) เราสร้างคุณสมบัติใหม่ ส่งผลให้เกิดการคอมมิตกับตัวระบุ #c1. เรารวบรวมและเผยแพร่ในรีจิสทรีโดยใช้ตัวระบุนี้ (#c1). ด้วยตัวระบุเดียวกันนี้ เราจึงเปิดตัวให้ดูตัวอย่าง เราทำเช่นเดียวกันกับการคอมมิต #c2 и #c3.

เมื่อเราตระหนักว่ามีคุณสมบัติเพียงพอ เราก็เริ่มทำให้ทุกอย่างมีเสถียรภาพ สร้างสาขาใน Git release_1.1 (บนฐาน #c3 ของ develop). ไม่จำเป็นต้องรวบรวมรุ่นนี้เพราะ... เสร็จสิ้นในขั้นตอนก่อนหน้า ดังนั้นเราจึงสามารถขยายไปสู่การแสดงละครได้ เราแก้ไขข้อบกพร่องใน #c4 และเปิดตัวสู่การแสดงละครในทำนองเดียวกัน ขณะเดียวกัน การพัฒนากำลังดำเนินอยู่ใน developโดยจะมีการนำการเปลี่ยนแปลงเป็นระยะๆ release_1.1. เมื่อถึงจุดหนึ่ง เราได้รับการคอมไพล์และอัปโหลดไปยังการแสดงละคร ซึ่งเราพอใจกับ (#c25).

จากนั้นเราจะรวม (ด้วยการกรอไปข้างหน้า) สาขาการเผยแพร่ (release_1.1) ในต้นแบบ เราใส่แท็กด้วยเวอร์ชันใหม่ในการคอมมิตนี้ (1.1). แต่รูปภาพนี้ถูกรวบรวมไว้ในรีจิสทรีแล้ว ดังนั้นเพื่อไม่ให้รวบรวมอีก เราเพียงเพิ่มแท็กที่สองให้กับรูปภาพที่มีอยู่ (ตอนนี้มีแท็กในรีจิสทรีแล้ว #c25 и 1.1). หลังจากนั้นเราก็เริ่มใช้งานจริง

มีข้อเสียเปรียบคือมีการอัปโหลดภาพเดียวไปยังการแสดงละคร (#c25) และในการผลิตจะแตกต่างออกไป (1.1) แต่เรารู้ว่า "ทางกายภาพ" เหล่านี้เป็นอิมเมจเดียวกันจากรีจิสตรี

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ข้อเสียที่แท้จริงคือไม่มีการรองรับการรวมคอมมิต คุณต้องกรอไปข้างหน้า

เราสามารถไปต่อและทำเคล็ดลับได้... ลองดูตัวอย่าง Dockerfile แบบง่ายๆ:

FROM ruby:2.3 as assets
RUN mkdir -p /app
WORKDIR /app
COPY . ./
RUN gem install bundler && bundle install
RUN bundle exec rake assets:precompile
CMD bundle exec puma -C config/puma.rb

FROM nginx:alpine
COPY --from=assets /app/public /usr/share/nginx/www/public

มาสร้างไฟล์จากมันตามหลักการต่อไปนี้:

  • SHA256 จากตัวระบุของรูปภาพที่ใช้ (ruby:2.3 и nginx:alpine) ซึ่งเป็นการตรวจสอบเนื้อหา
  • ทุกทีม (RUN, CMD และอื่นๆ.);
  • SHA256 จากไฟล์ที่เพิ่ม

... และนำเช็คซัม (SHA256 อีกครั้ง) จากไฟล์ดังกล่าว นี้ ลายเซ็น ทุกอย่างที่กำหนดเนื้อหาของอิมเมจ Docker

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

กลับไปที่แผนภาพและ แทนที่จะกระทำ เราจะใช้ลายเซ็นดังกล่าว, เช่น. แท็กรูปภาพพร้อมลายเซ็น

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ตอนนี้ เมื่อจำเป็น เช่น เพื่อรวมการเปลี่ยนแปลงจากรีลีสไปเป็นมาสเตอร์ เราสามารถดำเนินการผสานจริงได้ โดยจะมีตัวระบุที่แตกต่างกัน แต่มีลายเซ็นเดียวกัน ด้วยตัวระบุเดียวกัน เราจะเปิดตัวอิมเมจเป็นการใช้งานจริง

ข้อเสียคือตอนนี้ไม่สามารถระบุได้ว่า Commit ประเภทใดที่ถูกผลักไปสู่การใช้งานจริง - เช็คซัมจะทำงานในทิศทางเดียวเท่านั้น ปัญหานี้แก้ไขได้ด้วยเลเยอร์เพิ่มเติมพร้อมข้อมูลเมตา - ฉันจะแจ้งให้คุณทราบเพิ่มเติมในภายหลัง

การแท็กใน welf

ใน Werf เราไปไกลกว่านั้นและกำลังเตรียมที่จะสร้างบิวด์แบบกระจายด้วยแคชที่ไม่ได้จัดเก็บไว้ในเครื่องเดียว... ดังนั้นเราจึงสร้างอิมเมจ Docker สองประเภท เราเรียกมันว่าพวกมัน เวที и ภาพ.

พื้นที่เก็บข้อมูล werf Git จัดเก็บคำสั่งเฉพาะของบิลด์ที่อธิบายขั้นตอนต่างๆ ของบิลด์ (ก่อนทำการติดตั้ง, ติดตั้ง, ก่อนการตั้งค่า, การติดตั้ง). เรารวบรวมภาพขั้นแรกพร้อมลายเซ็นที่กำหนดให้เป็นผลรวมตรวจสอบของขั้นตอนแรก จากนั้นเราเพิ่มซอร์สโค้ด สำหรับอิมเมจสเตจใหม่ เราจะคำนวณผลรวมตรวจสอบ... การดำเนินการเหล่านี้จะทำซ้ำในทุกสเตจ ซึ่งส่งผลให้เราได้รับชุดของอิมเมจสเตจ จากนั้นเราจะสร้างภาพสุดท้ายซึ่งมีข้อมูลเมตาเกี่ยวกับที่มาของภาพด้วย และเราแท็กรูปภาพนี้ด้วยวิธีต่างๆ (รายละเอียดภายหลัง)

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

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

ดังนั้น รูปภาพสเตจจึงเป็นแคชที่สามารถจัดเก็บแบบกระจายได้ และรูปภาพที่สร้างไว้แล้วจากนั้นจะถูกอัปโหลดไปยัง Docker Registry

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ทำความสะอาดรีจิสทรี

เราไม่ได้พูดถึงการลบเลเยอร์ที่ยังคงค้างหลังจากแท็กที่ถูกลบ - นี่เป็นคุณสมบัติมาตรฐานของ Docker Registry เอง เรากำลังพูดถึงสถานการณ์ที่แท็ก Docker จำนวนมากสะสมและเราเข้าใจว่าเราไม่ต้องการแท็กเหล่านี้อีกต่อไป แต่แท็กเหล่านั้นกินพื้นที่ (และ/หรือเราจ่ายเงินเอง)

กลยุทธ์การทำความสะอาดมีอะไรบ้าง?

  1. คุณไม่สามารถทำอะไรได้เลย อย่าทำความสะอาด. บางครั้งการจ่ายเงินเพียงเล็กน้อยเพื่อซื้อพื้นที่เพิ่มเติมก็ง่ายกว่าการแก้แท็กที่ยุ่งวุ่นวาย แต่วิธีนี้ใช้ได้ผลถึงจุดหนึ่งเท่านั้น
  2. รีเซ็ตเต็ม. หากคุณลบอิมเมจทั้งหมดและสร้างใหม่เฉพาะอิมเมจปัจจุบันในระบบ CI ปัญหาอาจเกิดขึ้น หากรีสตาร์ทคอนเทนเนอร์ในการผลิต อิมเมจใหม่จะถูกโหลดสำหรับคอนเทนเนอร์นั้น - อิมเมจที่ยังไม่ได้ทดสอบโดยใครเลย สิ่งนี้ทำลายแนวคิดเรื่องโครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป
  3. ฟ้าเขียว. รีจิสทรีรายการหนึ่งเริ่มล้น - เราอัปโหลดรูปภาพไปยังอีกรายการหนึ่ง ปัญหาเดียวกับวิธีก่อนหน้า: คุณสามารถล้างรีจิสทรีที่เริ่มล้นได้เมื่อใด
  4. ตามเวลา. ลบรูปภาพทั้งหมดที่เก่ากว่า 1 เดือนหรือไม่ แต่จะมีบริการที่ไม่ได้อัพเดทมาเป็นเดือนแน่นอนครับ...
  5. ด้วยมือ กำหนดสิ่งที่สามารถลบได้แล้ว

มีสองตัวเลือกที่เป็นไปได้อย่างแท้จริง: ห้ามทำความสะอาดหรือผสมสีน้ำเงินเขียว + ด้วยตนเอง ในกรณีหลังเรากำลังพูดถึงสิ่งต่อไปนี้: เมื่อคุณเข้าใจว่าถึงเวลาที่ต้องทำความสะอาดรีจิสทรี คุณจะสร้างอันใหม่และเพิ่มรูปภาพใหม่ทั้งหมดลงในนั้นภายในระยะเวลาหนึ่งเดือน เช่น หนึ่งเดือน และหลังจากผ่านไปหนึ่งเดือน ให้ดูว่าพ็อดใดใน Kubernetes ที่ยังคงใช้รีจิสทรีเก่าอยู่ และโอนไปยังรีจิสทรีใหม่ด้วย

เรามาทำอะไร. เวร? เรารวบรวม:

  1. Git head: แท็กทั้งหมด, ทุกสาขา - สมมติว่าเราต้องการทุกสิ่งที่แท็กใน Git ในภาพ (และถ้าไม่ใช่ เราต้องลบมันใน Git เอง)
  2. พ็อดทั้งหมดที่ถูกสูบออกไปยัง Kubernetes ในปัจจุบัน
  3. ReplicaSets เก่า (ซึ่งเพิ่งเปิดตัว) และเรายังวางแผนที่จะสแกน Helm รุ่นต่างๆ และเลือกรูปภาพล่าสุดที่นั่น

... และจัดทำไวท์ลิสต์จากชุดนี้ - รายการภาพที่เราจะไม่ลบ เราทำความสะอาดสิ่งอื่นๆ ออกไป หลังจากนั้นเราจะพบภาพบนเวทีเด็กกำพร้าและลบออกด้วย

ปรับใช้ขั้นตอน

การประกาศที่เชื่อถือได้

จุดแรกที่ฉันต้องการดึงดูดความสนใจในการปรับใช้คือการเปิดตัวการกำหนดค่าทรัพยากรที่อัปเดต ซึ่งมีการประกาศอย่างเปิดเผย เอกสาร YAML ต้นฉบับที่อธิบายทรัพยากร Kubernetes จะแตกต่างจากผลลัพธ์ที่ทำงานจริงในคลัสเตอร์อย่างมากเสมอ เนื่องจาก Kubernetes เพิ่มการกำหนดค่า:

  1. ตัวระบุ;
  2. ข้อมูลการบริการ
  3. ค่าเริ่มต้นมากมาย
  4. ส่วนที่มีสถานะปัจจุบัน
  5. การเปลี่ยนแปลงที่ทำโดยเป็นส่วนหนึ่งของ webhook การรับเข้าเรียน
  6. ผลลัพธ์ของการทำงานของคอนโทรลเลอร์ต่างๆ (และตัวกำหนดเวลา)

ดังนั้น เมื่อการกำหนดค่าทรัพยากรใหม่ปรากฏขึ้น (ใหม่) เราไม่สามารถรับและเขียนทับการกำหนดค่าปัจจุบัน "สด" ด้วย (สด). ในการทำเช่นนี้เราจะต้องเปรียบเทียบ ใหม่ ด้วยการกำหนดค่าที่ใช้ล่าสุด (ใช้ครั้งสุดท้าย) และกลิ้งไป สด ได้รับแพทช์แล้ว

วิธีนี้เรียกว่า ผสาน 2 ทาง. มันถูกใช้ใน Helm เป็นต้น

นอกจากนี้ยังมี ผสาน 3 ทางซึ่งแตกต่างจากที่:

  • การเปรียบเทียบ ใช้ครั้งสุดท้าย и ใหม่เราดูสิ่งที่ถูกลบไป
  • การเปรียบเทียบ ใหม่ и สดเรามาดูกันว่ามีอะไรเพิ่มหรือเปลี่ยนแปลงบ้าง
  • ใช้แพทช์สรุปผลกับ สด.

เราปรับใช้แอปพลิเคชันมากกว่า 1000 รายการกับ Helm ดังนั้นเราจึงใช้ชีวิตด้วยการผสานแบบ 2 ทาง อย่างไรก็ตาม มันมีปัญหาหลายประการที่เราได้แก้ไขด้วยแพตช์ของเรา ซึ่งช่วยให้ Helm ทำงานได้ตามปกติ

สถานะการเปิดตัวจริง

หลังจากที่ระบบ CI ของเราสร้างการกำหนดค่าใหม่สำหรับ Kubernetes ตามเหตุการณ์ถัดไป ระบบจะส่งข้อมูลดังกล่าวเพื่อใช้งาน (นำมาใช้) ไปยังคลัสเตอร์ - ใช้ Helm หรือ kubectl apply. ถัดไป การรวม N-way ที่อธิบายไว้แล้วเกิดขึ้น ซึ่ง Kubernetes API ตอบสนองต่อระบบ CI อย่างอนุมัติ และตอบสนองต่อผู้ใช้ด้วย

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

อย่างไรก็ตามมีปัญหาใหญ่อยู่: หลังจากนั้น การสมัครที่ประสบความสำเร็จไม่ได้หมายถึงการเปิดตัวที่ประสบความสำเร็จ. หาก Kubernetes เข้าใจว่าการเปลี่ยนแปลงใดบ้างที่จำเป็นต้องนำไปใช้และนำไปใช้ เราก็ไม่รู้ว่าผลลัพธ์จะเป็นอย่างไร ตัวอย่างเช่น การอัปเดตและการรีสตาร์ทพ็อดในส่วนหน้าอาจทำได้สำเร็จ แต่ไม่สามารถทำได้ในแบ็กเอนด์ และเราจะได้อิมเมจแอปพลิเคชันที่ทำงานอยู่เวอร์ชันต่างๆ

ในการทำทุกอย่างอย่างถูกต้อง โครงการนี้จำเป็นต้องมีลิงก์เพิ่มเติม - ตัวติดตามพิเศษที่จะรับข้อมูลสถานะจาก Kubernetes API และส่งไปเพื่อวิเคราะห์สถานะที่แท้จริงของสิ่งต่าง ๆ เพิ่มเติม เราสร้างไลบรารี Open Source ใน Go - คิวบ์ด็อก (ดูประกาศของมัน ที่นี่)ซึ่งแก้ปัญหานี้และสร้างไว้ใน wef

ลักษณะการทำงานของตัวติดตามนี้ในระดับ wef ได้รับการกำหนดค่าโดยใช้คำอธิบายประกอบที่วางอยู่บน Deployments หรือ StatefulSets คำอธิบายประกอบหลัก - fail-mode - เข้าใจความหมายดังต่อไปนี้:

  • IgnoreAndContinueDeployProcess — เราเพิกเฉยต่อปัญหาในการเปิดตัวส่วนประกอบนี้และดำเนินการปรับใช้ต่อไป
  • FailWholeDeployProcessImmediately — ข้อผิดพลาดในองค์ประกอบนี้จะหยุดกระบวนการปรับใช้
  • HopeUntilEndOfDeployProcess — เราหวังว่าส่วนประกอบนี้จะทำงานได้เมื่อสิ้นสุดการปรับใช้

ตัวอย่างเช่น การรวมกันของทรัพยากรและค่าคำอธิบายประกอบนี้ fail-mode:

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

เมื่อเราปรับใช้เป็นครั้งแรก ฐานข้อมูล (MongoDB) อาจยังไม่พร้อม - การปรับใช้จะล้มเหลว แต่คุณสามารถรอสักครู่เพื่อให้เริ่มต้นได้ และการปรับใช้จะยังคงเกิดขึ้น

มีคำอธิบายประกอบอีกสองรายการสำหรับ kubedog ใน werf:

  • failures-allowed-per-replica - จำนวนการล้มที่อนุญาตสำหรับแต่ละแบบจำลอง
  • show-logs-until — ควบคุมช่วงเวลาที่ werf แสดงบันทึก (ใน stdout) จากพ็อดที่เผยแพร่ทั้งหมด ค่าเริ่มต้นคือ PodIsReady (เพื่อละเว้นข้อความที่เราอาจไม่ต้องการเมื่อการรับส่งข้อมูลเริ่มมาที่พ็อด) แต่ค่าก็ถูกต้องเช่นกัน: ControllerIsReady и EndOfDeploy.

เราต้องการอะไรอีกจากการปรับใช้?

นอกเหนือจากสองประเด็นที่อธิบายไปแล้ว เรายังต้องการ:

  • ดู บันทึก - และเฉพาะที่จำเป็นเท่านั้นไม่ใช่ทุกอย่างติดต่อกัน
  • ติดตาม ความคืบหน้าเพราะถ้างานค้าง “เงียบๆ” เป็นเวลาหลายนาที สิ่งสำคัญคือต้องเข้าใจว่าเกิดอะไรขึ้นที่นั่น
  • иметь ย้อนกลับอัตโนมัติ ในกรณีที่มีบางอย่างผิดพลาด (และดังนั้นจึงจำเป็นอย่างยิ่งที่จะต้องทราบสถานะที่แท้จริงของการปรับใช้) การเปิดตัวจะต้องเป็นแบบอะตอมมิก: ไม่ว่าจะดำเนินไปจนจบหรือทุกอย่างจะกลับสู่สถานะก่อนหน้า

ผลของการ

สำหรับเราในฐานะบริษัท หากต้องการใช้ความแตกต่างที่อธิบายไว้ในขั้นตอนต่างๆ ของการจัดส่ง (สร้าง เผยแพร่ ปรับใช้) ระบบ CI และยูทิลิตี้ก็เพียงพอแล้ว เวร.

แทนที่จะเป็นข้อสรุป:

werf - เครื่องมือของเราสำหรับ CI / CD ใน Kubernetes (รายงานภาพรวมและวิดีโอ)

ด้วยความช่วยเหลือของ werf เรามีความก้าวหน้าที่ดีในการแก้ไขปัญหาจำนวนมากสำหรับวิศวกร DevOps และยินดีเป็นอย่างยิ่งหากชุมชนในวงกว้างได้ลองใช้ยูทิลิตี้นี้อย่างน้อยที่สุด จะได้ผลลัพธ์ที่ดีร่วมกันได้ง่ายขึ้น

วิดีโอและสไลด์

วิดีโอจากการแสดง (~47 นาที):

การนำเสนอรายงาน:

PS

รายงานอื่นๆ เกี่ยวกับ Kubernetes ในบล็อกของเรา:

ที่มา: will.com

เพิ่มความคิดเห็น