เรื่องราวนี้เป็นเรื่องเกี่ยวกับวิธีที่เราใช้คอนเทนเนอร์ในสภาพแวดล้อมการใช้งานจริง โดยเฉพาะ Kubernetes บทความนี้มีเนื้อหาเกี่ยวกับการรวบรวมตัววัดและบันทึกจากคอนเทนเนอร์ รวมถึงการสร้างอิมเมจ
เรามาจากบริษัทฟินเทค Exness ซึ่งพัฒนาบริการสำหรับการซื้อขายออนไลน์และผลิตภัณฑ์ฟินเทคสำหรับ B2B และ B2C R&D ของเรามีทีมที่แตกต่างกันมากมาย แผนกพัฒนามีพนักงานมากกว่า 100 คน
เราเป็นตัวแทนของทีมที่รับผิดชอบแพลตฟอร์มสำหรับนักพัฒนาของเราในการรวบรวมและเรียกใช้โค้ด โดยเฉพาะอย่างยิ่ง เรามีหน้าที่รับผิดชอบในการรวบรวม จัดเก็บ และรายงานตัวชี้วัด บันทึก และกิจกรรมจากแอปพลิเคชัน ขณะนี้เราใช้งานคอนเทนเนอร์ Docker ประมาณสามพันคอนเทนเนอร์ในสภาพแวดล้อมการใช้งานจริง รักษาพื้นที่จัดเก็บข้อมูลขนาดใหญ่ 50 TB ของเรา และจัดหาโซลูชันทางสถาปัตยกรรมที่สร้างขึ้นรอบๆ โครงสร้างพื้นฐานของเรา: Kubernetes, Rancher และผู้ให้บริการคลาวด์สาธารณะต่างๆ
แรงจูงใจของเรา
อะไรกำลังไหม้? ไม่มีใครสามารถตอบได้ เตาไฟอยู่ที่ไหน? มันยากที่จะเข้าใจ ไฟไหม้เมื่อไหร่? คุณสามารถค้นหาได้ แต่ไม่ใช่ในทันที
ทำไมบางตู้ถึงยืนได้แต่บางตู้ก็ล้ม? ภาชนะใดที่ถูกตำหนิ? ท้ายที่สุดแล้วด้านนอกของคอนเทนเนอร์จะเหมือนกัน แต่ภายในแต่ละคอนเทนเนอร์จะมีนีโอของตัวเอง
นักพัฒนาของเราเป็นคนที่มีความสามารถ พวกเขาให้บริการที่ดีซึ่งนำผลกำไรมาสู่บริษัท แต่มีความล้มเหลวเมื่อคอนเทนเนอร์ที่มีแอปพลิเคชันหลงทาง คอนเทนเนอร์หนึ่งใช้ CPU มากเกินไป อีกคอนเทนเนอร์หนึ่งใช้เครือข่าย คอนเทนเนอร์ตัวที่สามใช้การดำเนินการ I/O และคอนเทนเนอร์ตัวที่สี่ไม่มีความชัดเจนเลยว่ามันทำอะไรกับซ็อกเก็ต ทุกอย่างพังและเรือก็จม
ตัวแทน
เพื่อให้เข้าใจถึงสิ่งที่เกิดขึ้นภายใน เราจึงตัดสินใจวางตัวแทนไว้ในคอนเทนเนอร์โดยตรง
ตัวแทนเหล่านี้เป็นโปรแกรมควบคุมที่จะรักษาคอนเทนเนอร์ให้อยู่ในสภาพที่ไม่แตกหักซึ่งกันและกัน ตัวแทนได้รับมาตรฐาน และช่วยให้มีแนวทางที่เป็นมาตรฐานในการให้บริการคอนเทนเนอร์
ในกรณีของเรา ตัวแทนจะต้องจัดเตรียมบันทึกในรูปแบบมาตรฐาน ติดแท็ก และควบคุมปริมาณ นอกจากนี้ยังควรจัดเตรียมหน่วยวัดมาตรฐานที่สามารถขยายได้จากมุมมองของแอปพลิเคชันทางธุรกิจอีกด้วย
ตัวแทนยังหมายถึงยูทิลิตี้สำหรับการดำเนินงานและการบำรุงรักษาที่สามารถทำงานในระบบการจัดการที่แตกต่างกันซึ่งรองรับอิมเมจที่แตกต่างกัน (Debian, Alpine, Centos ฯลฯ)
สุดท้ายนี้ เจ้าหน้าที่จะต้องสนับสนุน CI/CD แบบง่ายที่มีไฟล์ Docker มิฉะนั้นเรือจะพังเพราะตู้คอนเทนเนอร์จะเริ่มจัดส่งไปตามราง "คดเคี้ยว"
กระบวนการสร้างและอุปกรณ์ภาพเป้าหมาย
เพื่อให้ทุกอย่างเป็นมาตรฐานและจัดการได้ จำเป็นต้องปฏิบัติตามกระบวนการสร้างมาตรฐานบางประเภท ดังนั้นเราจึงตัดสินใจรวบรวมคอนเทนเนอร์ตามคอนเทนเนอร์ - นี่คือการเรียกซ้ำ
ที่นี่ตู้คอนเทนเนอร์จะแสดงด้วยโครงร่างทึบ ในเวลาเดียวกัน พวกเขาตัดสินใจใส่ชุดแจกจ่ายเพื่อที่ว่า “ชีวิตจะไม่เหมือนราสเบอร์รี่” เหตุใดจึงทำเช่นนี้ เราจะอธิบายด้านล่าง
ผลลัพธ์ที่ได้คือเครื่องมือสร้าง ซึ่งเป็นคอนเทนเนอร์เฉพาะเวอร์ชันที่อ้างอิงเวอร์ชันการแจกจ่ายเฉพาะและเวอร์ชันสคริปต์เฉพาะ
เราจะใช้มันอย่างไร? เรามี Docker Hub ที่มีคอนเทนเนอร์ เราจำลองมันภายในระบบของเราเพื่อกำจัดการพึ่งพาภายนอก ผลที่ได้คือภาชนะที่ทำเครื่องหมายเป็นสีเหลือง เราสร้างเทมเพลตเพื่อติดตั้งการแจกแจงและสคริปต์ทั้งหมดที่เราต้องการลงในคอนเทนเนอร์ หลังจากนั้น เราจะรวบรวมอิมเมจที่พร้อมใช้งาน: นักพัฒนาใส่โค้ดและการอ้างอิงพิเศษบางอย่างลงไป
แนวทางนี้มีประโยชน์อย่างไร?
- ขั้นแรก การควบคุมเวอร์ชันเต็มของเครื่องมือสร้าง - สร้างเวอร์ชันคอนเทนเนอร์ สคริปต์ และเวอร์ชันการแจกจ่าย
- ประการที่สอง เราได้รับมาตรฐาน: เราสร้างเทมเพลต รูปภาพระดับกลางและพร้อมใช้งานในลักษณะเดียวกัน
- ประการที่สาม ตู้คอนเทนเนอร์ทำให้เราพกพาสะดวก วันนี้เราใช้ Gitlab และพรุ่งนี้เราจะเปลี่ยนไปใช้ TeamCity หรือ Jenkins และเราจะสามารถรันคอนเทนเนอร์ของเราในลักษณะเดียวกันได้
- ประการที่สี่ ลดการพึ่งพาอาศัยกัน ไม่ใช่เรื่องบังเอิญที่เราใส่ชุดแจกจ่ายลงในคอนเทนเนอร์ เนื่องจากจะทำให้เราหลีกเลี่ยงการดาวน์โหลดจากอินเทอร์เน็ตทุกครั้ง
- ประการที่ห้า ความเร็วในการสร้างเพิ่มขึ้น - การมีสำเนารูปภาพในเครื่องช่วยให้คุณหลีกเลี่ยงการเสียเวลาในการดาวน์โหลดเนื่องจากมีรูปภาพในเครื่อง
กล่าวอีกนัยหนึ่ง เราได้รับกระบวนการประกอบที่มีการควบคุมและยืดหยุ่น เราใช้เครื่องมือเดียวกันเพื่อสร้างคอนเทนเนอร์เวอร์ชันเต็ม
ขั้นตอนการสร้างของเราทำงานอย่างไร
แอสเซมบลีเปิดตัวด้วยคำสั่งเดียว กระบวนการจะดำเนินการในภาพ (เน้นด้วยสีแดง) นักพัฒนามีไฟล์ Docker (เน้นด้วยสีเหลือง) เราเรนเดอร์มันโดยแทนที่ตัวแปรด้วยค่า และตลอดทางที่เราเพิ่มส่วนหัวและส่วนท้าย - นี่คือตัวแทนของเรา
ส่วนหัวเพิ่มการแจกแจงจากรูปภาพที่เกี่ยวข้อง และส่วนท้ายจะติดตั้งบริการของเราภายใน กำหนดค่าการเปิดใช้งานปริมาณงาน การบันทึก และตัวแทนอื่นๆ แทนที่จุดเข้าใช้งาน ฯลฯ
เราคิดอยู่นานว่าจะติดตั้งหัวหน้างานหรือไม่ ในที่สุดเราก็ตัดสินใจว่าเราต้องการเขา เราเลือก S6 หัวหน้างานจัดเตรียมการจัดการคอนเทนเนอร์: ช่วยให้คุณสามารถเชื่อมต่อกับคอนเทนเนอร์ได้หากกระบวนการหลักขัดข้องและให้การจัดการคอนเทนเนอร์ด้วยตนเองโดยไม่ต้องสร้างใหม่ บันทึกและหน่วยเมตริกเป็นกระบวนการที่ทำงานภายในคอนเทนเนอร์ พวกเขายังจำเป็นต้องได้รับการควบคุมด้วย และเราดำเนินการนี้โดยได้รับความช่วยเหลือจากหัวหน้างาน สุดท้ายนี้ S6 จะดูแลการดูแลทำความสะอาด การประมวลผลสัญญาณ และงานอื่นๆ
เนื่องจากเราใช้ระบบการจัดการที่แตกต่างกัน หลังจากสร้างและใช้งานแล้ว คอนเทนเนอร์จะต้องเข้าใจว่าคอนเทนเนอร์นั้นอยู่ในสภาพแวดล้อมใดและดำเนินการตามสถานการณ์ ตัวอย่างเช่น:
สิ่งนี้ช่วยให้เราสามารถสร้างอิมเมจหนึ่งภาพและเรียกใช้ในระบบออร์เคสตราที่แตกต่างกัน และจะเปิดตัวโดยคำนึงถึงลักษณะเฉพาะของระบบออร์เคสตรานี้
สำหรับคอนเทนเนอร์เดียวกัน เราจะได้แผนผังกระบวนการที่แตกต่างกันใน Docker และ Kubernetes:
เพย์โหลดจะดำเนินการภายใต้การดูแลของ S6 ให้ความสนใจกับนักสะสมและกิจกรรมต่างๆ - สิ่งเหล่านี้คือตัวแทนของเราที่รับผิดชอบบันทึกและตัวชี้วัด Kubernetes ไม่มี แต่ Docker มี ทำไม
หากเราดูข้อมูลจำเพาะของ “พ็อด” (ต่อไปนี้เรียกว่าพ็อด Kubernetes) เราจะเห็นว่าคอนเทนเนอร์เหตุการณ์ถูกดำเนินการในพ็อด ซึ่งมีคอนเทนเนอร์ตัวรวบรวมแยกต่างหากที่ทำหน้าที่รวบรวมเมตริกและบันทึก เราสามารถใช้ความสามารถของ Kubernetes ได้ เช่น การรันคอนเทนเนอร์ในพ็อดเดียว ในกระบวนการเดียว และ/หรือพื้นที่เครือข่าย แนะนำตัวแทนของคุณและทำหน้าที่บางอย่างจริงๆ และหากคอนเทนเนอร์เดียวกันเปิดตัวใน Docker คอนเทนเนอร์จะได้รับความสามารถเดียวกันกับเอาต์พุต กล่าวคือ คอนเทนเนอร์จะสามารถส่งบันทึกและเมตริกได้ เนื่องจากเอเจนต์จะเปิดตัวภายใน
ตัวชี้วัดและบันทึก
การส่งมอบตัววัดและบันทึกเป็นงานที่ซับซ้อน การตัดสินใจของเธอมีหลายแง่มุม
โครงสร้างพื้นฐานถูกสร้างขึ้นสำหรับการดำเนินการเพย์โหลด ไม่ใช่สำหรับการจัดส่งบันทึกจำนวนมาก นั่นคือ กระบวนการนี้จะต้องดำเนินการโดยมีความต้องการทรัพยากรคอนเทนเนอร์น้อยที่สุด เรามุ่งมั่นที่จะช่วยเหลือนักพัฒนาของเรา: “รับคอนเทนเนอร์ Docker Hub เรียกใช้ แล้วเราจะส่งมอบบันทึกได้”
ด้านที่สองคือการจำกัดปริมาณของบันทึก หากปริมาณบันทึกเพิ่มขึ้นอย่างรวดเร็วในหลายคอนเทนเนอร์ (แอปพลิเคชันส่งออกการติดตามสแต็กในลูป) โหลดบน CPU ช่องทางการสื่อสาร และระบบประมวลผลบันทึกจะเพิ่มขึ้น และสิ่งนี้ส่งผลต่อการทำงานของโฮสต์ในฐานะ ทั้งหมดและคอนเทนเนอร์อื่น ๆ บนโฮสต์ จากนั้นบางครั้งสิ่งนี้นำไปสู่การ "ล่มสลาย" ของโฮสต์
ประเด็นที่สามคือจำเป็นต้องสนับสนุนวิธีการรวบรวมตัวชี้วัดให้ได้มากที่สุดเท่าที่จะทำได้ ตั้งแต่การอ่านไฟล์และการโพล Prometheus-endpoint ไปจนถึงการใช้โปรโตคอลเฉพาะแอปพลิเคชัน
และประการสุดท้ายคือการลดการใช้ทรัพยากรให้เหลือน้อยที่สุด
เราเลือกโซลูชัน Go แบบโอเพ่นซอร์สที่เรียกว่า Telegraf นี่คือตัวเชื่อมต่อสากลที่รองรับช่องอินพุตมากกว่า 140 ประเภท (ปลั๊กอินอินพุต) และช่องเอาต์พุต 30 ประเภท (ปลั๊กอินเอาต์พุต) เราได้สรุปแล้ว และตอนนี้เราจะบอกคุณว่าเราใช้งานอย่างไรโดยใช้ Kubernetes เป็นตัวอย่าง
สมมติว่านักพัฒนาปรับใช้ปริมาณงานและ Kubernetes ได้รับคำขอให้สร้างพ็อด ณ จุดนี้ คอนเทนเนอร์ที่เรียกว่า Collector จะถูกสร้างขึ้นโดยอัตโนมัติสำหรับแต่ละพ็อด (เราใช้ webhook ที่กลายพันธุ์) นักสะสมคือตัวแทนของเรา ในตอนเริ่มต้น คอนเทนเนอร์นี้จะกำหนดค่าตัวเองให้ทำงานกับ Prometheus และระบบรวบรวมบันทึก
- เมื่อต้องการทำเช่นนี้ จะใช้คำอธิบายประกอบของพ็อด และขึ้นอยู่กับเนื้อหา จะสร้างจุดสิ้นสุดของโพร
- โดยขึ้นอยู่กับข้อกำหนดเฉพาะของพ็อดและการตั้งค่าคอนเทนเนอร์ที่เฉพาะเจาะจง จะตัดสินใจว่าจะส่งบันทึกอย่างไร
เรารวบรวมบันทึกผ่าน Docker API: นักพัฒนาเพียงแค่ต้องใส่บันทึกเหล่านั้นใน stdout หรือ stderr แล้ว Collector จะจัดเรียงมัน บันทึกจะถูกรวบรวมเป็นชิ้นโดยมีความล่าช้าเพื่อป้องกันโฮสต์โอเวอร์โหลดที่อาจเกิดขึ้น
ตัววัดจะถูกรวบรวมระหว่างอินสแตนซ์ปริมาณงาน (กระบวนการ) ในคอนเทนเนอร์ ทุกอย่างถูกแท็ก: เนมสเปซ ใต้ และอื่นๆ จากนั้นแปลงเป็นรูปแบบ Prometheus และพร้อมสำหรับการรวบรวม (ยกเว้นบันทึก) นอกจากนี้เรายังส่งบันทึก ตัวชี้วัด และเหตุการณ์ไปยัง Kafka และอื่นๆ:
- บันทึกมีอยู่ใน Graylog (สำหรับการวิเคราะห์ด้วยภาพ)
- บันทึก ตัวชี้วัด กิจกรรมจะถูกส่งไปยัง Clickhouse เพื่อจัดเก็บข้อมูลระยะยาว
ทุกอย่างทำงานเหมือนกันทุกประการใน AWS มีเพียงเราเท่านั้นที่แทนที่ Graylog ด้วย Kafka ด้วย Cloudwatch เราส่งบันทึกไปที่นั่น และทุกอย่างก็ดูสะดวกมาก: เห็นได้ชัดเจนว่าคลัสเตอร์และคอนเทนเนอร์ใดอยู่ในกลุ่มใด เช่นเดียวกับ Google Stackdriver นั่นคือแผนของเราทำงานได้ทั้งภายในองค์กรกับ Kafka และในระบบคลาวด์
ถ้าเราไม่มี Kubernetes ที่มีพ็อด โครงการนี้จะซับซ้อนกว่าเล็กน้อย แต่ก็ใช้หลักการเดียวกันได้
กระบวนการเดียวกันนี้ดำเนินการภายในคอนเทนเนอร์ โดยมีการเรียบเรียงโดยใช้ S6 กระบวนการเดียวกันทั้งหมดกำลังทำงานอยู่ภายในคอนเทนเนอร์เดียวกัน
เป็นผลให้
เราได้สร้างโซลูชันที่สมบูรณ์สำหรับการสร้างและเปิดใช้งานอิมเมจ พร้อมตัวเลือกสำหรับการรวบรวมและส่งมอบบันทึกและตัวชี้วัด:
- เราได้พัฒนาแนวทางที่เป็นมาตรฐานในการประกอบภาพ และจากแนวทางนั้น เราได้พัฒนาเทมเพลต CI;
- เจ้าหน้าที่รวบรวมข้อมูลคือส่วนขยาย Telegraf ของเรา เราทดสอบพวกมันอย่างดีในการผลิต
- เราใช้ webhook ที่กลายพันธุ์เพื่อใช้งานคอนเทนเนอร์กับเอเจนต์ในพ็อด
- บูรณาการเข้ากับระบบนิเวศ Kubernetes/Rancher
- เราสามารถรันคอนเทนเนอร์เดียวกันในระบบการจัดการที่แตกต่างกัน และได้ผลลัพธ์ตามที่เราคาดหวัง
- สร้างการกำหนดค่าการจัดการคอนเทนเนอร์แบบไดนามิกโดยสมบูรณ์
ผู้เขียนร่วม: อิลยา พรูดนิคอฟ
ที่มา: will.com