วันที่ 27 พฤษภาคม ณ ห้องโถงหลักของการประชุม DevOpsConf 2019 ซึ่งจัดขึ้นเป็นส่วนหนึ่งของเทศกาล
นับตั้งแต่การนำเสนอ ยูทิลิตี้ของเรา (เดิมชื่อ dapp) ได้ก้าวไปสู่เหตุการณ์สำคัญทางประวัติศาสตร์ของ 1000 ดาวบน GitHub — เราหวังว่าชุมชนผู้ใช้ที่กำลังเติบโตนี้จะทำให้ชีวิตของวิศวกร DevOps หลายคนง่ายขึ้น
เอาล่ะ เรามาแนะนำกันดีกว่า
การส่งโค้ดไปยัง Kubernetes
การพูดคุยจะไม่เกี่ยวกับ werf อีกต่อไป แต่เกี่ยวกับ CI/CD ใน Kubernetes ซึ่งหมายความว่าซอฟต์แวร์ของเราได้รับการบรรจุในคอนเทนเนอร์ Docker (ผมพูดถึงเรื่องนี้ใน.
การจัดส่งมีลักษณะอย่างไรใน Kubernetes
- มีพื้นที่เก็บข้อมูล Git พร้อมโค้ดและคำแนะนำในการสร้าง แอปพลิเคชันนี้สร้างไว้ในอิมเมจ Docker และเผยแพร่ใน Docker Registry
- พื้นที่เก็บข้อมูลเดียวกันนี้ยังมีคำแนะนำเกี่ยวกับวิธีการปรับใช้และรันแอปพลิเคชันอีกด้วย ในขั้นตอนการปรับใช้ คำแนะนำเหล่านี้จะถูกส่งไปยัง Kubernetes ซึ่งรับอิมเมจที่ต้องการจากรีจิสทรีและเปิดใช้งาน
- นอกจากนี้ก็มักจะมีการทดสอบ สิ่งเหล่านี้บางส่วนสามารถทำได้เมื่อเผยแพร่รูปภาพ คุณยังสามารถ (ทำตามคำแนะนำเดียวกัน) ปรับใช้สำเนาของแอปพลิเคชันได้ (ในเนมสเปซ K8s ที่แยกต่างหากหรือคลัสเตอร์ที่แยกต่างหาก) และทำการทดสอบที่นั่น
- สุดท้ายนี้ คุณต้องมีระบบ CI ที่รับเหตุการณ์จาก Git (หรือการคลิกปุ่ม) และเรียกขั้นตอนที่กำหนดทั้งหมด: สร้าง เผยแพร่ ปรับใช้ ทดสอบ
มีหมายเหตุสำคัญบางประการที่นี่:
- เพราะเรามีโครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป (โครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป), อิมเมจแอปพลิเคชันที่ใช้ในทุกขั้นตอน (การจัดเตรียม, การผลิต ฯลฯ) จะต้องมีอย่างใดอย่างหนึ่ง. ฉันพูดคุยเกี่ยวกับเรื่องนี้โดยละเอียดและพร้อมตัวอย่าง
ที่นี่ . - เพราะเราปฏิบัติตามโครงสร้างพื้นฐานเป็นแนวทางการเขียนโค้ด (ไอเอซี), รหัสแอปพลิเคชัน, คำแนะนำในการประกอบและเปิดใช้ควรจะเป็น อยู่ในที่เก็บข้อมูลเดียว. สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ โปรดดู
รายงานเดียวกัน . - ห่วงโซ่อุปทาน (จัดส่ง) เรามักจะเห็นแบบนี้ คือ แอปพลิเคชันถูกประกอบ ทดสอบ และเผยแพร่ (ระยะปล่อยตัว) เท่านี้ก็เรียบร้อย - มีการส่งมอบแล้ว แต่ในความเป็นจริง ผู้ใช้จะได้รับสิ่งที่คุณเปิดตัว ไม่ แล้วเมื่อคุณส่งมอบมันให้กับการผลิต และเมื่อเขาสามารถไปที่นั่นได้และการผลิตนี้ก็ได้ผล ฉันจึงเชื่อว่าห่วงโซ่การส่งมอบสิ้นสุดลง ในขั้นตอนการปฏิบัติงานเท่านั้น (วิ่ง)หรือแม่นยำยิ่งขึ้นแม้ในขณะที่รหัสถูกลบออกจากการผลิต (แทนที่ด้วยรหัสใหม่)
กลับไปที่รูปแบบการจัดส่งข้างต้นใน Kubernetes: มันไม่ได้ถูกคิดค้นโดยเราเท่านั้น แต่โดยทุกคนที่จัดการกับปัญหานี้อย่างแท้จริง จริงๆ แล้ว รูปแบบนี้เรียกว่า GitOps (คุณสามารถอ่านเพิ่มเติมเกี่ยวกับคำศัพท์และแนวคิดเบื้องหลังได้
สร้างเวที
ดูเหมือนว่าคุณจะสามารถพูดคุยเกี่ยวกับการสร้างอิมเมจ Docker ได้ในปี 2019 เมื่อทุกคนรู้วิธีเขียน Dockerfiles และเรียกใช้ docker build
?.. นี่คือความแตกต่างที่ฉันอยากจะใส่ใจ:
- น้ำหนักภาพ สำคัญดังนั้นใช้
หลายขั้นตอน เพื่อเหลือไว้ในรูปภาพเฉพาะแอปพลิเคชันที่จำเป็นจริงๆ สำหรับการดำเนินการ - จำนวนชั้น จะต้องย่อให้เล็กสุดโดยการรวมโซ่ของ
RUN
-คำสั่งตามความหมาย - อย่างไรก็ตาม สิ่งนี้จะเพิ่มปัญหา การดีบักเพราะเมื่อแอสเซมบลีล้มเหลวคุณต้องค้นหาคำสั่งที่ถูกต้องจากเชนที่ทำให้เกิดปัญหา
- ความเร็วในการประกอบ สำคัญเพราะเราต้องการเปิดตัวการเปลี่ยนแปลงอย่างรวดเร็วและดูผลลัพธ์ ตัวอย่างเช่น คุณไม่ต้องการสร้างการขึ้นต่อกันในไลบรารีภาษาทุกครั้งที่คุณสร้างแอปพลิเคชัน
- บ่อยครั้งจากพื้นที่เก็บข้อมูล Git เดียวที่คุณต้องการ หลายภาพซึ่งสามารถแก้ไขได้โดยชุดของ Dockerfiles (หรือสเตจที่มีชื่อในไฟล์เดียว) และสคริปต์ Bash พร้อมแอสเซมบลีตามลำดับ
นี่เป็นเพียงยอดภูเขาน้ำแข็งที่ทุกคนเผชิญ แต่มีปัญหาอื่น ๆ โดยเฉพาะ:
- บ่อยครั้งในขั้นตอนการประกอบ เราต้องการบางสิ่งบางอย่าง เมานต์ (เช่น แคชผลลัพธ์ของคำสั่ง เช่น apt ในไดเร็กทอรีบุคคลที่สาม)
- พวกเราต้องการ เบิ้ล แทนที่จะเขียนในเชลล์
- พวกเราต้องการ สร้างโดยไม่มีนักเทียบท่า (เหตุใดเราจึงต้องมีเครื่องเสมือนเพิ่มเติมซึ่งเราต้องกำหนดค่าทุกอย่างสำหรับสิ่งนี้ ในเมื่อเรามีคลัสเตอร์ Kubernetes ซึ่งเราสามารถเรียกใช้คอนเทนเนอร์ได้แล้ว)
- การประกอบแบบขนานซึ่งสามารถเข้าใจได้หลายวิธี: คำสั่งที่แตกต่างจาก Dockerfile (หากใช้หลายขั้นตอน), คอมมิตหลายอันจากที่เก็บเดียวกัน, Dockerfile หลายอัน
- การประกอบแบบกระจาย: เราอยากสะสมของในฝักที่ "ชั่วคราว" เพราะว่า แคชหายไปซึ่งหมายความว่าจำเป็นต้องจัดเก็บไว้ที่ใดที่หนึ่งแยกกัน
- ในที่สุดฉันก็ตั้งชื่อจุดสุดยอดของความปรารถนา มายากลอัตโนมัติ: เป็นการดีที่จะไปที่ Repository พิมพ์คำสั่งบางอย่างแล้วได้ภาพสำเร็จรูปประกอบกับความเข้าใจว่าต้องทำอย่างไรและอย่างไรให้ถูกต้อง อย่างไรก็ตามโดยส่วนตัวแล้วฉันไม่แน่ใจว่าสามารถคาดการณ์ความแตกต่างทั้งหมดได้ด้วยวิธีนี้
และนี่คือโครงการ:
-
โมบี้/บิลด์คิท — เครื่องมือสร้างจาก Docker Inc (รวมเข้ากับ Docker เวอร์ชันปัจจุบันแล้ว) ซึ่งพยายามแก้ไขปัญหาเหล่านี้ทั้งหมด -
คานิโกะ — เครื่องมือสร้างจาก Google ที่ให้คุณสร้างโดยไม่ต้องใช้ Docker -
Buildpacks.io — ความพยายามของ CNCF ในการสร้างเวทย์มนตร์อัตโนมัติ และโดยเฉพาะอย่างยิ่ง โซลูชั่นที่น่าสนใจพร้อมการรีเบสสำหรับเลเยอร์ - และสาธารณูปโภคอื่นๆ อีกมากมาย เช่น
บิวดาห์ ,เครื่องมือของแท้/img ...
...และดูว่าพวกเขามีดาวกี่ดวงบน GitHub กล่าวคือ ในด้านหนึ่ง docker build
มีอยู่และสามารถทำอะไรบางอย่างได้แต่ในความเป็นจริง ปัญหายังไม่ได้รับการแก้ไขอย่างสมบูรณ์ - ข้อพิสูจน์เรื่องนี้คือการพัฒนาแบบคู่ขนานของตัวสะสมทางเลือก ซึ่งแต่ละตัวสามารถแก้ปัญหาได้บางส่วน
การประกอบใน WRF
ดังนั้นเราจึงต้อง
ปัญหาที่แรเงาสีน้ำเงินได้ถูกนำมาใช้แล้ว การสร้างแบบคู่ขนานเสร็จสิ้นภายในโฮสต์เดียวกัน และปัญหาที่เน้นด้วยสีเหลืองมีแผนจะแล้วเสร็จภายในสิ้นฤดูร้อน
ขั้นตอนการตีพิมพ์ในทะเบียน (เผยแพร่)
เราโทรไป docker push
... - การอัพโหลดรูปภาพไปยังรีจิสตรีอาจเป็นเรื่องยากอะไร แล้วคำถามก็เกิดขึ้น: “ฉันควรใส่แท็กอะไรในภาพ?” มันเกิดขึ้นเพราะเหตุที่เรามี Gitflow (หรือกลยุทธ์ Git อื่นๆ) และ Kubernetes และอุตสาหกรรมกำลังพยายามให้แน่ใจว่าสิ่งที่เกิดขึ้นใน Kubernetes จะเป็นไปตามสิ่งที่เกิดขึ้นใน Git ท้ายที่สุดแล้ว Git เป็นแหล่งความจริงเพียงแหล่งเดียวของเรา
อะไรจะยากขนาดนี้? มั่นใจในการทำซ้ำ: จากการกระทำใน Git ซึ่งมีลักษณะไม่เปลี่ยนรูป (ไม่เปลี่ยนรูป)ไปยังอิมเมจ Docker ซึ่งควรคงไว้เหมือนเดิม
มันเป็นสิ่งสำคัญสำหรับเราเช่นกัน กำหนดแหล่งกำเนิดเนื่องจากเราต้องการทำความเข้าใจว่าแอปพลิเคชันใดที่รันใน Kubernetes ถูกสร้างขึ้น (จากนั้นเราสามารถทำสิ่งที่แตกต่างและสิ่งที่คล้ายกันได้)
กลยุทธ์การแท็ก
อันแรกนั้นง่าย แท็กคอมไพล์. เรามีรีจิสทรีพร้อมรูปภาพที่แท็กเป็น 1.0
. Kubernetes มีขั้นตอนและการผลิตซึ่งจะมีการอัปโหลดรูปภาพนี้ ใน Git เราทำการคอมมิตและเมื่อถึงจุดหนึ่งเราก็แท็ก 2.0
. เรารวบรวมมันตามคำแนะนำจากพื้นที่เก็บข้อมูลและวางไว้ในรีจิสตรีพร้อมแท็ก 2.0
. เราเปิดตัวบนเวที และหากทุกอย่างเรียบร้อยดี เราก็เข้าสู่การผลิต
ปัญหาของแนวทางนี้คือเราใส่แท็กก่อน จากนั้นจึงทดสอบและเผยแพร่เท่านั้น ทำไม ประการแรก มันไร้เหตุผล: เรากำลังออกซอฟต์แวร์เวอร์ชันที่เรายังไม่ได้ทดสอบด้วยซ้ำ (เราทำอย่างอื่นไม่ได้ เนื่องจากในการตรวจสอบ เราต้องใส่แท็ก) ประการที่สอง เส้นทางนี้เข้ากันไม่ได้กับ 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
) แต่เรารู้ว่า "ทางกายภาพ" เหล่านี้เป็นอิมเมจเดียวกันจากรีจิสตรี
ข้อเสียที่แท้จริงคือไม่มีการรองรับการรวมคอมมิต คุณต้องกรอไปข้างหน้า
เราสามารถไปต่อและทำเคล็ดลับได้... ลองดูตัวอย่าง 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
กลับไปที่แผนภาพและ แทนที่จะกระทำ เราจะใช้ลายเซ็นดังกล่าว, เช่น. แท็กรูปภาพพร้อมลายเซ็น
ตอนนี้ เมื่อจำเป็น เช่น เพื่อรวมการเปลี่ยนแปลงจากรีลีสไปเป็นมาสเตอร์ เราสามารถดำเนินการผสานจริงได้ โดยจะมีตัวระบุที่แตกต่างกัน แต่มีลายเซ็นเดียวกัน ด้วยตัวระบุเดียวกัน เราจะเปิดตัวอิมเมจเป็นการใช้งานจริง
ข้อเสียคือตอนนี้ไม่สามารถระบุได้ว่า Commit ประเภทใดที่ถูกผลักไปสู่การใช้งานจริง - เช็คซัมจะทำงานในทิศทางเดียวเท่านั้น ปัญหานี้แก้ไขได้ด้วยเลเยอร์เพิ่มเติมพร้อมข้อมูลเมตา - ฉันจะแจ้งให้คุณทราบเพิ่มเติมในภายหลัง
การแท็กใน welf
ใน Werf เราไปไกลกว่านั้นและกำลังเตรียมที่จะสร้างบิวด์แบบกระจายด้วยแคชที่ไม่ได้จัดเก็บไว้ในเครื่องเดียว... ดังนั้นเราจึงสร้างอิมเมจ Docker สองประเภท เราเรียกมันว่าพวกมัน เวที и ภาพ.
พื้นที่เก็บข้อมูล werf Git จัดเก็บคำสั่งเฉพาะของบิลด์ที่อธิบายขั้นตอนต่างๆ ของบิลด์ (ก่อนทำการติดตั้ง, ติดตั้ง, ก่อนการตั้งค่า, การติดตั้ง). เรารวบรวมภาพขั้นแรกพร้อมลายเซ็นที่กำหนดให้เป็นผลรวมตรวจสอบของขั้นตอนแรก จากนั้นเราเพิ่มซอร์สโค้ด สำหรับอิมเมจสเตจใหม่ เราจะคำนวณผลรวมตรวจสอบ... การดำเนินการเหล่านี้จะทำซ้ำในทุกสเตจ ซึ่งส่งผลให้เราได้รับชุดของอิมเมจสเตจ จากนั้นเราจะสร้างภาพสุดท้ายซึ่งมีข้อมูลเมตาเกี่ยวกับที่มาของภาพด้วย และเราแท็กรูปภาพนี้ด้วยวิธีต่างๆ (รายละเอียดภายหลัง)
สมมติว่าหลังจากนี้การคอมมิตใหม่จะปรากฏขึ้นโดยมีการเปลี่ยนแปลงเฉพาะโค้ดแอปพลิเคชันเท่านั้น อะไรจะเกิดขึ้น? สำหรับการเปลี่ยนแปลงโค้ด จะมีการสร้างแพตช์และเตรียมสเตจอิมเมจใหม่ ลายเซ็นจะถูกกำหนดเป็นการตรวจสอบของอิมเมจบนเวทีเก่าและแพทช์ใหม่ ภาพสุดท้ายใหม่จะถูกสร้างขึ้นจากภาพนี้ พฤติกรรมที่คล้ายกันนี้จะเกิดขึ้นพร้อมกับการเปลี่ยนแปลงในระยะอื่น
ดังนั้น รูปภาพสเตจจึงเป็นแคชที่สามารถจัดเก็บแบบกระจายได้ และรูปภาพที่สร้างไว้แล้วจากนั้นจะถูกอัปโหลดไปยัง Docker Registry
ทำความสะอาดรีจิสทรี
เราไม่ได้พูดถึงการลบเลเยอร์ที่ยังคงค้างหลังจากแท็กที่ถูกลบ - นี่เป็นคุณสมบัติมาตรฐานของ Docker Registry เอง เรากำลังพูดถึงสถานการณ์ที่แท็ก Docker จำนวนมากสะสมและเราเข้าใจว่าเราไม่ต้องการแท็กเหล่านี้อีกต่อไป แต่แท็กเหล่านั้นกินพื้นที่ (และ/หรือเราจ่ายเงินเอง)
กลยุทธ์การทำความสะอาดมีอะไรบ้าง?
- คุณไม่สามารถทำอะไรได้เลย อย่าทำความสะอาด. บางครั้งการจ่ายเงินเพียงเล็กน้อยเพื่อซื้อพื้นที่เพิ่มเติมก็ง่ายกว่าการแก้แท็กที่ยุ่งวุ่นวาย แต่วิธีนี้ใช้ได้ผลถึงจุดหนึ่งเท่านั้น
- รีเซ็ตเต็ม. หากคุณลบอิมเมจทั้งหมดและสร้างใหม่เฉพาะอิมเมจปัจจุบันในระบบ CI ปัญหาอาจเกิดขึ้น หากรีสตาร์ทคอนเทนเนอร์ในการผลิต อิมเมจใหม่จะถูกโหลดสำหรับคอนเทนเนอร์นั้น - อิมเมจที่ยังไม่ได้ทดสอบโดยใครเลย สิ่งนี้ทำลายแนวคิดเรื่องโครงสร้างพื้นฐานที่ไม่เปลี่ยนรูป
- ฟ้าเขียว. รีจิสทรีรายการหนึ่งเริ่มล้น - เราอัปโหลดรูปภาพไปยังอีกรายการหนึ่ง ปัญหาเดียวกับวิธีก่อนหน้า: คุณสามารถล้างรีจิสทรีที่เริ่มล้นได้เมื่อใด
- ตามเวลา. ลบรูปภาพทั้งหมดที่เก่ากว่า 1 เดือนหรือไม่ แต่จะมีบริการที่ไม่ได้อัพเดทมาเป็นเดือนแน่นอนครับ...
- ด้วยมือ กำหนดสิ่งที่สามารถลบได้แล้ว
มีสองตัวเลือกที่เป็นไปได้อย่างแท้จริง: ห้ามทำความสะอาดหรือผสมสีน้ำเงินเขียว + ด้วยตนเอง ในกรณีหลังเรากำลังพูดถึงสิ่งต่อไปนี้: เมื่อคุณเข้าใจว่าถึงเวลาที่ต้องทำความสะอาดรีจิสทรี คุณจะสร้างอันใหม่และเพิ่มรูปภาพใหม่ทั้งหมดลงในนั้นภายในระยะเวลาหนึ่งเดือน เช่น หนึ่งเดือน และหลังจากผ่านไปหนึ่งเดือน ให้ดูว่าพ็อดใดใน Kubernetes ที่ยังคงใช้รีจิสทรีเก่าอยู่ และโอนไปยังรีจิสทรีใหม่ด้วย
เรามาทำอะไร. เวร? เรารวบรวม:
- Git head: แท็กทั้งหมด, ทุกสาขา - สมมติว่าเราต้องการทุกสิ่งที่แท็กใน Git ในภาพ (และถ้าไม่ใช่ เราต้องลบมันใน Git เอง)
- พ็อดทั้งหมดที่ถูกสูบออกไปยัง Kubernetes ในปัจจุบัน
- ReplicaSets เก่า (ซึ่งเพิ่งเปิดตัว) และเรายังวางแผนที่จะสแกน Helm รุ่นต่างๆ และเลือกรูปภาพล่าสุดที่นั่น
... และจัดทำไวท์ลิสต์จากชุดนี้ - รายการภาพที่เราจะไม่ลบ เราทำความสะอาดสิ่งอื่นๆ ออกไป หลังจากนั้นเราจะพบภาพบนเวทีเด็กกำพร้าและลบออกด้วย
ปรับใช้ขั้นตอน
การประกาศที่เชื่อถือได้
จุดแรกที่ฉันต้องการดึงดูดความสนใจในการปรับใช้คือการเปิดตัวการกำหนดค่าทรัพยากรที่อัปเดต ซึ่งมีการประกาศอย่างเปิดเผย เอกสาร YAML ต้นฉบับที่อธิบายทรัพยากร Kubernetes จะแตกต่างจากผลลัพธ์ที่ทำงานจริงในคลัสเตอร์อย่างมากเสมอ เนื่องจาก Kubernetes เพิ่มการกำหนดค่า:
- ตัวระบุ;
- ข้อมูลการบริการ
- ค่าเริ่มต้นมากมาย
- ส่วนที่มีสถานะปัจจุบัน
- การเปลี่ยนแปลงที่ทำโดยเป็นส่วนหนึ่งของ webhook การรับเข้าเรียน
- ผลลัพธ์ของการทำงานของคอนโทรลเลอร์ต่างๆ (และตัวกำหนดเวลา)
ดังนั้น เมื่อการกำหนดค่าทรัพยากรใหม่ปรากฏขึ้น (ใหม่) เราไม่สามารถรับและเขียนทับการกำหนดค่าปัจจุบัน "สด" ด้วย (สด). ในการทำเช่นนี้เราจะต้องเปรียบเทียบ ใหม่ ด้วยการกำหนดค่าที่ใช้ล่าสุด (ใช้ครั้งสุดท้าย) และกลิ้งไป สด ได้รับแพทช์แล้ว
วิธีนี้เรียกว่า ผสาน 2 ทาง. มันถูกใช้ใน Helm เป็นต้น
นอกจากนี้ยังมี ผสาน 3 ทางซึ่งแตกต่างจากที่:
- การเปรียบเทียบ ใช้ครั้งสุดท้าย и ใหม่เราดูสิ่งที่ถูกลบไป
- การเปรียบเทียบ ใหม่ и สดเรามาดูกันว่ามีอะไรเพิ่มหรือเปลี่ยนแปลงบ้าง
- ใช้แพทช์สรุปผลกับ สด.
เราปรับใช้แอปพลิเคชันมากกว่า 1000 รายการกับ Helm ดังนั้นเราจึงใช้ชีวิตด้วยการผสานแบบ 2 ทาง อย่างไรก็ตาม มันมีปัญหาหลายประการที่เราได้แก้ไขด้วยแพตช์ของเรา ซึ่งช่วยให้ Helm ทำงานได้ตามปกติ
สถานะการเปิดตัวจริง
หลังจากที่ระบบ CI ของเราสร้างการกำหนดค่าใหม่สำหรับ Kubernetes ตามเหตุการณ์ถัดไป ระบบจะส่งข้อมูลดังกล่าวเพื่อใช้งาน (นำมาใช้) ไปยังคลัสเตอร์ - ใช้ Helm หรือ kubectl apply
. ถัดไป การรวม N-way ที่อธิบายไว้แล้วเกิดขึ้น ซึ่ง Kubernetes API ตอบสนองต่อระบบ CI อย่างอนุมัติ และตอบสนองต่อผู้ใช้ด้วย
อย่างไรก็ตามมีปัญหาใหญ่อยู่: หลังจากนั้น การสมัครที่ประสบความสำเร็จไม่ได้หมายถึงการเปิดตัวที่ประสบความสำเร็จ. หาก Kubernetes เข้าใจว่าการเปลี่ยนแปลงใดบ้างที่จำเป็นต้องนำไปใช้และนำไปใช้ เราก็ไม่รู้ว่าผลลัพธ์จะเป็นอย่างไร ตัวอย่างเช่น การอัปเดตและการรีสตาร์ทพ็อดในส่วนหน้าอาจทำได้สำเร็จ แต่ไม่สามารถทำได้ในแบ็กเอนด์ และเราจะได้อิมเมจแอปพลิเคชันที่ทำงานอยู่เวอร์ชันต่างๆ
ในการทำทุกอย่างอย่างถูกต้อง โครงการนี้จำเป็นต้องมีลิงก์เพิ่มเติม - ตัวติดตามพิเศษที่จะรับข้อมูลสถานะจาก Kubernetes API และส่งไปเพื่อวิเคราะห์สถานะที่แท้จริงของสิ่งต่าง ๆ เพิ่มเติม เราสร้างไลบรารี Open Source ใน Go -
ลักษณะการทำงานของตัวติดตามนี้ในระดับ wef ได้รับการกำหนดค่าโดยใช้คำอธิบายประกอบที่วางอยู่บน Deployments หรือ StatefulSets คำอธิบายประกอบหลัก - fail-mode
- เข้าใจความหมายดังต่อไปนี้:
-
IgnoreAndContinueDeployProcess
— เราเพิกเฉยต่อปัญหาในการเปิดตัวส่วนประกอบนี้และดำเนินการปรับใช้ต่อไป -
FailWholeDeployProcessImmediately
— ข้อผิดพลาดในองค์ประกอบนี้จะหยุดกระบวนการปรับใช้ -
HopeUntilEndOfDeployProcess
— เราหวังว่าส่วนประกอบนี้จะทำงานได้เมื่อสิ้นสุดการปรับใช้
ตัวอย่างเช่น การรวมกันของทรัพยากรและค่าคำอธิบายประกอบนี้ fail-mode
:
เมื่อเราปรับใช้เป็นครั้งแรก ฐานข้อมูล (MongoDB) อาจยังไม่พร้อม - การปรับใช้จะล้มเหลว แต่คุณสามารถรอสักครู่เพื่อให้เริ่มต้นได้ และการปรับใช้จะยังคงเกิดขึ้น
มีคำอธิบายประกอบอีกสองรายการสำหรับ kubedog ใน werf:
-
failures-allowed-per-replica
- จำนวนการล้มที่อนุญาตสำหรับแต่ละแบบจำลอง -
show-logs-until
— ควบคุมช่วงเวลาที่ werf แสดงบันทึก (ใน stdout) จากพ็อดที่เผยแพร่ทั้งหมด ค่าเริ่มต้นคือPodIsReady
(เพื่อละเว้นข้อความที่เราอาจไม่ต้องการเมื่อการรับส่งข้อมูลเริ่มมาที่พ็อด) แต่ค่าก็ถูกต้องเช่นกัน:ControllerIsReady
иEndOfDeploy
.
เราต้องการอะไรอีกจากการปรับใช้?
นอกเหนือจากสองประเด็นที่อธิบายไปแล้ว เรายังต้องการ:
- ดู บันทึก - และเฉพาะที่จำเป็นเท่านั้นไม่ใช่ทุกอย่างติดต่อกัน
- ติดตาม ความคืบหน้าเพราะถ้างานค้าง “เงียบๆ” เป็นเวลาหลายนาที สิ่งสำคัญคือต้องเข้าใจว่าเกิดอะไรขึ้นที่นั่น
- иметь ย้อนกลับอัตโนมัติ ในกรณีที่มีบางอย่างผิดพลาด (และดังนั้นจึงจำเป็นอย่างยิ่งที่จะต้องทราบสถานะที่แท้จริงของการปรับใช้) การเปิดตัวจะต้องเป็นแบบอะตอมมิก: ไม่ว่าจะดำเนินไปจนจบหรือทุกอย่างจะกลับสู่สถานะก่อนหน้า
ผลของการ
สำหรับเราในฐานะบริษัท หากต้องการใช้ความแตกต่างที่อธิบายไว้ในขั้นตอนต่างๆ ของการจัดส่ง (สร้าง เผยแพร่ ปรับใช้) ระบบ CI และยูทิลิตี้ก็เพียงพอแล้ว
แทนที่จะเป็นข้อสรุป:
ด้วยความช่วยเหลือของ werf เรามีความก้าวหน้าที่ดีในการแก้ไขปัญหาจำนวนมากสำหรับวิศวกร DevOps และยินดีเป็นอย่างยิ่งหากชุมชนในวงกว้างได้ลองใช้ยูทิลิตี้นี้อย่างน้อยที่สุด จะได้ผลลัพธ์ที่ดีร่วมกันได้ง่ายขึ้น
วิดีโอและสไลด์
วิดีโอจากการแสดง (~47 นาที):
การนำเสนอรายงาน:
PS
รายงานอื่นๆ เกี่ยวกับ Kubernetes ในบล็อกของเรา:
- «
การปรับขนาดอัตโนมัติและการจัดการทรัพยากรใน Kubernetes » (Dmitry Stolyarov; 27 เมษายน 2019 ใน “Strike”); - «
การขยายและการเสริม Kubernetes » (Andrey Polovov; 8 เมษายน 2019 บน Saint HighLoad++); - «
ฐานข้อมูลและ Kubernetes » (Dmitry Stolyarov; 8 พฤศจิกายน 2018 บน HighLoad++); - «
การตรวจสอบและ Kubernetes » (Dmitry Stolyarov; 28 พฤษภาคม 2018 ที่ RootConf); - «
แนวทางปฏิบัติที่ดีที่สุดของ CI/CD กับ Kubernetes และ GitLab » (Dmitry Stolyarov; 7 พฤศจิกายน 2017 บน HighLoad++); - «
ประสบการณ์ของเรากับ Kubernetes ในโครงการขนาดเล็ก » (Dmitry Stolyarov; 6 มิถุนายน 2017 ที่ RootConf).
ที่มา: will.com