ฉันมีโครงการขนาดกลางแล้วตอนนี้ใกล้จะสิ้นสุด "เฟสต้นแบบที่ขับเคลื่อนด้วยคาเฟอีนแบบเลอะเทอะสำหรับการสาธิตลูกค้า" และเปลี่ยนเป็นเฟส "คิดเกี่ยวกับอนาคต" โครงการประกอบด้วยอุปกรณ์ที่ใช้ Linux พร้อมซอฟต์แวร์และเฟิร์มแวร์และเว็บเซิร์ฟเวอร์การบริหารส่วนกลาง 10 ต้นแบบที่มีอยู่ในปัจจุบันการผลิตคาดว่าจะอยู่ในลำดับต่ำ 1,000
การไม่ได้มีความเชี่ยวชาญในการอัปเดตอัตโนมัติและเป็นระยะเวลาสั้น ๆ ฉันได้เปิดตัวการปรับใช้ซอฟต์แวร์ / กลยุทธ์การอัพเดทอัตโนมัติอย่างรวดเร็วและตรงไปตรงมามันแย่มาก ปัจจุบันประกอบด้วยดังต่อไปนี้:
- git repo โฮสต์ (GitLab) ที่มีสาขารีลีสการผลิต (หมายเหตุแหล่งที่มาของเว็บเซิร์ฟเวอร์นั้นอยู่ใน repo เดียวกันนี้รวมถึงสิ่งอื่น ๆ อีกสองสามรายการ)
- ปุ่ม "ปรับใช้การอัปเดต" บนเว็บอินเตอร์เฟสที่:
- ดึงเวอร์ชันล่าสุดจากสาขารีลีสการผลิตไปยังพื้นที่ repo ท้องถิ่นและคัดลอกไปยังพื้นที่จัดเตรียมชั่วคราว
- รันสคริปต์การฆ่าเชื้อ (เก็บไว้ใน repo) ในพื้นที่จัดเตรียมเพื่อลบไฟล์ต้นฉบับที่ไม่เกี่ยวข้อง (เช่นแหล่งเซิร์ฟเวอร์, แหล่งเฟิร์มแวร์ ฯลฯ ) และไฟล์. git
- เขียนแฮช git ปัจจุบันไปยังไฟล์ในแพ็คเกจการอัพเดท (จุดประสงค์จะชัดเจนด้านล่าง)
- หากทุกอย่างเป็นไปด้วยดีมันจะบีบอัดไฟล์และทำให้พร้อมที่จะให้บริการโดยเขียนทับแพ็กเกจ gzipped ก่อนหน้าด้วยไฟล์ชื่อเดียวกันจากนั้นลบพื้นที่จัดเตรียม
- โปรดทราบว่าขณะนี้มีซอฟต์แวร์อุปกรณ์ปัจจุบันสองสำเนาบนเซิร์ฟเวอร์ซึ่งคาดว่าจะซิงค์: repo git ภายในเต็มรูปแบบในสาขาการผลิตล่าสุดและแพคเกจ gzipped ที่พร้อมใช้งานซึ่งตอนนี้สันนิษฐานว่าเป็นตัวแทนของ รุ่นเดียวกัน
- ซอฟต์แวร์ในอุปกรณ์นั้นมีอยู่ในไดเรกทอรีชื่อ
/opt/example/current
ซึ่งเป็น symlink ของซอฟต์แวร์รุ่นปัจจุบัน - ฟังก์ชั่นอัพเดทอัตโนมัติบนอุปกรณ์ที่บู๊ต:
- ตรวจสอบการมี
do_not_update
ไฟล์และไม่มีการดำเนินการเพิ่มเติมหากมีอยู่ (สำหรับอุปกรณ์ dev ดูด้านล่าง) - อ่านแฮชการคอมมิชชันปัจจุบันจากไฟล์ข้อความที่กล่าวถึงข้างต้น
- ทำให้คำร้องขอ HTTP ไปยังเซิร์ฟเวอร์โดยใช้แฮชนั้นเป็นพารามิเตอร์เคียวรี เซิร์ฟเวอร์จะตอบกลับด้วย 304 (แฮชเป็นเวอร์ชันปัจจุบัน) หรือจะให้บริการแพ็คเกจการอัพเดต gzipped
- ติดตั้งแพ็คเกจการอัพเดทหากได้รับมา
/opt/example
โดย:stage
สกัดการปรับปรุงซอฟต์แวร์โฟลเดอร์ข้อมูลที่ชื่อ- การรันสคริปต์หลังการติดตั้งจากแพ็คเกจการอัปเดตที่ทำสิ่งต่าง ๆ เช่นทำการเปลี่ยนแปลงในท้องถิ่นที่จำเป็นสำหรับการอัปเดตนั้นเป็นต้น
- คัดลอกโฟลเดอร์ปัจจุบันของซอฟต์แวร์รูทไปที่
previous
(ลบที่มีอยู่previous
ก่อนหากมี) - คัดลอก
stage
โฟลเดอร์ไปที่latest
(ลบที่มีอยู่latest
ก่อนถ้ามี) - การสร้างความมั่นใจ
current
symlinklatest
ไปชี้ไปที่ - การรีบูตอุปกรณ์ (หากมีการอัพเดตเฟิร์มแวร์จะถูกนำไปใช้ในการรีบูต)
- ตรวจสอบการมี
นอกจากนี้ยังมีปัญหาการปรับใช้เริ่มต้นบนอุปกรณ์ที่สร้างขึ้นใหม่ อุปกรณ์นี้ใช้การ์ด SD ในปัจจุบัน (มีชุดของปัญหาอยู่นอกขอบเขตที่นี่) ดังนั้นกระบวนการนี้ประกอบด้วย:
- มีภาพ SD ที่มีซอฟต์แวร์เวอร์ชันก่อนหน้านี้ที่มีความเสถียร
- มีการสร้างการ์ด SD จากภาพนี้
- ในการบู๊ตครั้งแรกจะมีการกำหนดค่าเริ่มต้นสำหรับอุปกรณ์เฉพาะ (ตามหมายเลขซีเรียล) เป็นครั้งแรกจากนั้นตัวอัพเดตอัตโนมัติจะคว้าและติดตั้งเวอร์ชันล่าสุดของซอฟต์แวร์ที่ผลิตตามปกติ
นอกจากนี้ฉันต้องการการสนับสนุนสำหรับอุปกรณ์การพัฒนา สำหรับอุปกรณ์การพัฒนา:
- repo git ท้องถิ่นเต็มจะถูกเก็บไว้ในอุปกรณ์
current
จุด symlink ไปไดเรกทอรีการพัฒนา- มี
do_not_update
ไฟล์ในตัวเครื่องซึ่งป้องกันไม่ให้ตัวอัพเดตอัตโนมัติระเบิดรหัสการพัฒนาด้วยการอัพเดทการผลิต
ตอนนี้ขั้นตอนการปรับใช้มีวัตถุประสงค์ในทางทฤษฎีที่จะ:
- เมื่อรหัสพร้อมสำหรับการปรับใช้ให้กดมันไปยังสาขาที่วางจำหน่าย
- กดปุ่ม "ปรับใช้การปรับปรุง" บนเซิร์ฟเวอร์
- ขณะนี้การอัปเดตพร้อมใช้งานและอุปกรณ์จะอัปเดตอัตโนมัติในครั้งต่อไปที่พวกเขาตรวจสอบ
อย่างไรก็ตามมีตันของปัญหาที่เกิดขึ้นในการปฏิบัติ:
- รหัสเว็บเซิร์ฟเวอร์อยู่ใน repo เดียวกันกับรหัสอุปกรณ์และเซิร์ฟเวอร์มี repo git ในพื้นที่ที่ฉันเรียกใช้ รหัสเซิร์ฟเวอร์เว็บล่าสุดไม่ได้อยู่ในสาขาเดียวกันกับรหัสอุปกรณ์ล่าสุด โครงสร้างไดเรกทอรีมีปัญหา เมื่อปุ่ม "ปรับใช้การอัปเดต" ดึงเวอร์ชันล่าสุดออกมาจากสาขาการผลิตปุ่มนั้นจะดึงเข้าไปในไดเรกทอรีย่อยของรหัสเซิร์ฟเวอร์ ซึ่งหมายความว่าเมื่อฉันปรับใช้กับเซิร์ฟเวอร์ตั้งแต่เริ่มต้นฉันต้อง "seed" ไดเรกทอรีย่อยนี้ด้วยตนเองโดยการจับสาขาการผลิตอุปกรณ์ลงในนั้นเพราะอาจเกิดจากข้อผิดพลาดของผู้ใช้คอมไพล์ในส่วนของฉันถ้าฉันไม่พยายามปรับใช้ ดึงรหัสอุปกรณ์จากสาขาเว็บเซิร์ฟเวอร์ของไดเรกทอรีหลัก ฉันคิดว่าสิ่งนี้สามารถแก้ไขได้ด้วยการทำให้พื้นที่การแสดงละครไม่ใช่ไดเรกทอรีย่อยของ repo git ในเครื่องของเซิร์ฟเวอร์
- เว็บเซิร์ฟเวอร์ในปัจจุบันไม่ได้รักษาแฮชคอมไพล์ของซอฟต์แวร์อุปกรณ์อย่างต่อเนื่อง ในการเริ่มต้นเซิร์ฟเวอร์มันจะทำซ้ำ
git rev-parse HEAD
ในซอฟต์แวร์อุปกรณ์ภายในเครื่องเพื่อเรียกแฮชปัจจุบัน ด้วยเหตุผลที่ฉันไม่สามารถสรุปได้ว่านี่เป็นสาเหตุของข้อผิดพลาดทางตรรกะมากมายที่ฉันจะไม่อธิบายที่นี่พอเพียงเพื่อบอกว่าบางครั้งการรีสตาร์ทสกรูของเซิร์ฟเวอร์ขึ้นโดยเฉพาะถ้าเซิร์ฟเวอร์ใหม่และไม่มีการผลิต repo สาขาถูกดึงแล้ว ฉันจะแบ่งปันแหล่งที่มาสำหรับตรรกะนั้นอย่างมีความสุขหากได้รับการร้องขอ แต่โพสต์นี้จะยาวขึ้น - หากสคริปต์การทำให้ถูกสุขลักษณะ (ฝั่งเซิร์ฟเวอร์) ล้มเหลวด้วยเหตุผลบางอย่างแสดงว่าเซิร์ฟเวอร์ถูกทิ้งให้อยู่กับ repo ที่ทันสมัย แต่แพ็คเกจการอัพเดทที่ไม่ซิงค์ / ขาดหายไปจึง
git rev-parse HEAD
จะส่งคืนแฮชที่ไม่ตรงกับสิ่งที่เกิดขึ้นจริง ส่งไปยังอุปกรณ์และปัญหาที่นี่จะต้องแก้ไขด้วยตนเองในบรรทัดคำสั่งเซิร์ฟเวอร์ นั่นคือเซิร์ฟเวอร์ไม่ทราบว่าแพคเกจโปรแกรมปรับปรุงนั้นไม่ถูกต้อง แต่จะถือว่าเป็นเช่นนั้นโดยสุจริต เมื่อรวมกับจุดก่อนหน้านี้ทำให้เซิร์ฟเวอร์มีความเปราะบางอย่างยิ่งในทางปฏิบัติ - หนึ่งในปัญหาที่ใหญ่ที่สุดคือ : ขณะนี้ไม่มี daemon ตัวอัปเดตแยกกันทำงานอยู่บนอุปกรณ์ เนื่องจากภาวะแทรกซ้อนที่กำลังรอการเข้าถึงอินเทอร์เน็ตไร้สายเพื่อมาและแฮกเกอร์ในนาทีสุดท้ายมันเป็นซอฟต์แวร์ควบคุมอุปกรณ์หลักที่ตรวจสอบและอัปเดตอุปกรณ์ ซึ่งหมายความว่าหากเวอร์ชันที่ทดสอบไม่ดีทำให้เกิดการผลิตและซอฟต์แวร์ควบคุมไม่สามารถเริ่มทำงานได้อุปกรณ์ทั้งหมดที่มีอยู่จะถูกปิดกั้นเพราะมันไม่สามารถอัปเดตตัวเองได้อีกต่อไป นี่จะเป็นฝันร้ายที่แท้จริงในการผลิต ข้อตกลงเดียวกันสำหรับอุปกรณ์เดียวหากสูญเสียพลังงานในเวลาที่โชคร้าย
- ปัญหาที่สำคัญอื่น ๆ คือ : ไม่มีการสนับสนุนสำหรับการปรับปรุงที่เพิ่มขึ้น หากอุปกรณ์บอกว่าไม่ได้เปิดอยู่ครู่หนึ่งแล้วในครั้งต่อไปที่มีการอัพเดตอุปกรณ์จะข้ามรุ่นที่วางจำหน่ายจำนวนมากอุปกรณ์จะต้องสามารถทำการอัปเดตที่ข้ามเวอร์ชั่นได้โดยตรง ผลที่ตามมาของการปรับใช้นี้มีการปรับปรุงเป็นฝันร้ายของการทำให้แน่ใจว่าการปรับปรุงใด ๆ ที่สามารถนำมาใช้ด้านบนของรุ่นที่ผ่านมาที่กำหนดใด ๆ นอกจากนี้เนื่องจากแฮช git ใช้เพื่อระบุเวอร์ชันมากกว่าหมายเลขเวอร์ชันการเปรียบเทียบโดยย่อของเวอร์ชันเพื่อช่วยในการอัปเดตที่เพิ่มขึ้นจึงไม่สามารถทำได้ในขณะนี้
- ข้อกำหนดใหม่ที่ฉันไม่สนับสนุนในปัจจุบันคือจะมีตัวเลือกการกำหนดค่าต่ออุปกรณ์ (คู่คีย์ / ค่า) ที่ต้องกำหนดค่าในฝั่งเซิร์ฟเวอร์การดูแลระบบ ฉันไม่รังเกียจที่จะให้บริการตัวเลือกต่ออุปกรณ์เหล่านี้กลับไปยังอุปกรณ์ในคำขอ HTTP เดียวกับการอัปเดตซอฟต์แวร์ ทำให้มันเป็นคำขอ HTTP แยกต่างหากเสมอ
- มีความซับซ้อนเล็กน้อยเนื่องจากความจริงที่ว่ามีฮาร์ดแวร์สองรุ่น (และอื่น ๆ ในอนาคต) อยู่ เวอร์ชันปัจจุบันของฮาร์ดแวร์ถูกจัดเก็บเป็นตัวแปรสภาพแวดล้อมในภาพ SD เริ่มต้น (ไม่สามารถระบุตัวเองได้) และซอฟต์แวร์ทั้งหมดได้รับการออกแบบให้เข้ากันได้กับอุปกรณ์ทุกรุ่น เลือกอัพเดตเฟิร์มแวร์ตามตัวแปรสภาพแวดล้อมนี้และชุดอัพเดทประกอบด้วยเฟิร์มแวร์สำหรับฮาร์ดแวร์ทุกรุ่น ฉันสามารถอยู่กับสิ่งนี้ได้แม้ว่ามันจะเป็นเรื่องเล็กน้อย
- ขณะนี้ไม่มีวิธีอัปโหลดการอัปเดตไปยังอุปกรณ์ด้วยตนเอง (เรื่องสั้นสั้น ๆ อุปกรณ์เหล่านี้มีอะแดปเตอร์ไร้สายสองตัวในตัวหนึ่งตัวสำหรับเชื่อมต่อกับอินเทอร์เน็ตและอีกตัวในโหมด AP ที่ผู้ใช้ใช้เพื่อกำหนดค่าอุปกรณ์ในอนาคต ฉันตั้งใจจะเพิ่มฟังก์ชั่น "อัปเดตซอฟต์แวร์" ลงในเว็บอินเตอร์เฟสของอุปกรณ์) นี่ไม่ใช่เรื่องใหญ่ แต่มีผลกระทบกับวิธีการติดตั้งการปรับปรุงบางอย่าง
- กลุ่มของความผิดหวังอื่น ๆ และความไม่มั่นคงทั่วไป
ดังนั้น ... นั่นเป็นเวลานาน แต่คำถามของฉันยังคงเป็นเช่นนี้:
ฉันจะทำสิ่งนี้อย่างถูกต้องและปลอดภัยได้อย่างไร มีการปรับเปลี่ยนเล็กน้อยที่ฉันสามารถทำได้กับกระบวนการปัจจุบันของฉันหรือไม่? มีกลยุทธ์หรือระบบที่มีการทดสอบตามเวลาที่ฉันสามารถยกระดับเพื่อที่ฉันจะได้ไม่ต้องหมุนระบบอัพเดทเส็งเคร็งของตัวเองหรือไม่? หรือถ้าฉันต้องม้วนตัวเองสิ่งที่ต้องเป็นจริงคืออะไรเพื่อให้กระบวนการปรับใช้ / อัปเดตมีความปลอดภัยและประสบความสำเร็จ ฉันต้องรวมอุปกรณ์สำหรับการพัฒนาด้วย
ฉันหวังว่าคำถามจะชัดเจน ฉันรู้ว่ามันค่อนข้างคลุมเครือ แต่ฉันมั่นใจ 100% ว่านี่เป็นปัญหาที่ถูกแก้ไขก่อนหน้านี้และแก้ไขได้สำเร็จฉันไม่ทราบว่ากลยุทธ์ที่ยอมรับในปัจจุบันคืออะไร