แนวทางปฏิบัติที่ดีที่สุดสำหรับคอนเทนเนอร์ Kubernetes: การตรวจสุขภาพ

แนวทางปฏิบัติที่ดีที่สุดสำหรับคอนเทนเนอร์ Kubernetes: การตรวจสุขภาพ

TL; DR

  • เพื่อให้บรรลุความสามารถในการสังเกตคอนเทนเนอร์และไมโครเซอร์วิสในระดับสูง บันทึกและตัววัดหลักยังไม่เพียงพอ
  • เพื่อการฟื้นตัวที่รวดเร็วและความยืดหยุ่นที่เพิ่มขึ้น แอปพลิเคชันควรใช้หลักการสังเกตสูง (HOP)
  • ในระดับแอปพลิเคชัน NOP ต้องการ: การบันทึกที่เหมาะสม การตรวจสอบอย่างใกล้ชิด การตรวจสอบสุขภาพ และการติดตามประสิทธิภาพ/การเปลี่ยนแปลง
  • ใช้เช็คเป็นองค์ประกอบของ NOR การสอบสวนความพร้อม и livenessProbe คูเบอร์เนเตส

เทมเพลตการตรวจสุขภาพคืออะไร?

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

หลักการสังเกตสูง (HOP)

หลักการสังเกตได้สูงคือหนึ่งใน หลักการออกแบบการใช้งานแบบคอนเทนเนอร์. ในสถาปัตยกรรมไมโครเซอร์วิส บริการไม่สนใจว่าคำขอของพวกเขาได้รับการประมวลผลอย่างไร (และถูกต้องเช่นกัน) แต่สิ่งสำคัญคือวิธีที่พวกเขาได้รับการตอบกลับจากบริการที่รับ ตัวอย่างเช่น ในการตรวจสอบสิทธิ์ผู้ใช้ คอนเทนเนอร์หนึ่งจะส่งคำขอ HTTP ไปยังอีกคอนเทนเนอร์หนึ่ง โดยคาดหวังการตอบสนองในรูปแบบใดรูปแบบหนึ่ง แค่นั้นเอง PythonJS ยังสามารถประมวลผลคำขอได้ และ Python Flask ก็สามารถตอบสนองได้ คอนเทนเนอร์ก็เหมือนกับกล่องดำที่มีเนื้อหาซ่อนอยู่ซึ่งกันและกัน อย่างไรก็ตาม หลักการ NOP กำหนดให้แต่ละบริการเปิดเผยตำแหน่งข้อมูล API หลายจุด ซึ่งบ่งชี้ว่าจุดสิ้นสุดนั้นดีเพียงใด รวมถึงความพร้อมและสถานะการทนทานต่อข้อผิดพลาด Kubernetes ขอตัวบ่งชี้เหล่านี้เพื่อพิจารณาขั้นตอนถัดไปสำหรับการกำหนดเส้นทางและการปรับสมดุลโหลด

แอปพลิเคชันระบบคลาวด์ที่ออกแบบมาอย่างดีจะบันทึกเหตุการณ์หลักโดยใช้สตรีม I/O มาตรฐาน STDERR และ STDOUT ถัดมาคือบริการเสริม เช่น filebeat, logstash หรือ fluentd การส่งบันทึกไปยังระบบตรวจสอบแบบรวมศูนย์ (เช่น Prometheus) และระบบรวบรวมบันทึก (ชุดซอฟต์แวร์ ELK) แผนภาพด้านล่างแสดงวิธีการทำงานของแอปพลิเคชันระบบคลาวด์ตามรูปแบบการทดสอบความสมบูรณ์และหลักการสังเกตได้สูง

แนวทางปฏิบัติที่ดีที่สุดสำหรับคอนเทนเนอร์ Kubernetes: การตรวจสุขภาพ

จะใช้รูปแบบการตรวจสุขภาพใน Kubernetes ได้อย่างไร

เมื่อแกะกล่อง k8s จะตรวจสอบสถานะของพ็อดโดยใช้ตัวควบคุมตัวใดตัวหนึ่ง (การใช้งาน, ชุดแบบจำลอง, DaemonSets, ชุดเก็บสถานะ ฯลฯ ฯลฯ) เมื่อพบว่าพ็อดล้มลงด้วยเหตุผลบางประการ คอนโทรลเลอร์จะพยายามรีสตาร์ทหรือย้ายไปยังโหนดอื่น อย่างไรก็ตาม พ็อดอาจรายงานว่าเปิดใช้งานแล้ว แต่ตัวพ็อดเองไม่ทำงาน ยกตัวอย่าง: แอปพลิเคชันของคุณใช้ Apache เป็นเว็บเซิร์ฟเวอร์ คุณติดตั้งส่วนประกอบบนพ็อดหลายตัวของคลัสเตอร์ เนื่องจากไลบรารีได้รับการกำหนดค่าไม่ถูกต้อง คำขอทั้งหมดไปยังแอปพลิเคชันจึงตอบกลับด้วยรหัส 500 (ข้อผิดพลาดเซิร์ฟเวอร์ภายใน) เมื่อตรวจสอบการจัดส่งการตรวจสอบสถานะของพ็อดให้ผลลัพธ์สำเร็จ แต่ลูกค้าคิดแตกต่าง เราจะอธิบายสถานการณ์ที่ไม่พึงประสงค์นี้ดังนี้:

แนวทางปฏิบัติที่ดีที่สุดสำหรับคอนเทนเนอร์ Kubernetes: การตรวจสุขภาพ

ในตัวอย่างของเรา k8s ทำได้ ตรวจสอบฟังก์ชันการทำงาน. ในการตรวจสอบประเภทนี้ kubelet จะตรวจสอบสถานะของกระบวนการในคอนเทนเนอร์อย่างต่อเนื่อง เมื่อเขาเข้าใจว่ากระบวนการหยุดแล้ว เขาจะเริ่มต้นใหม่ หากข้อผิดพลาดสามารถแก้ไขได้โดยเพียงแค่รีสตาร์ทแอปพลิเคชัน และโปรแกรมได้รับการออกแบบให้ปิดระบบเมื่อมีข้อผิดพลาดใดๆ ก็ตาม การตรวจสุขภาพกระบวนการคือสิ่งเดียวที่คุณต้องปฏิบัติตาม NOP และรูปแบบการทดสอบสุขภาพ น่าเสียดายเพียงอย่างเดียวคือไม่ใช่ว่าข้อผิดพลาดทั้งหมดจะถูกกำจัดโดยการรีสตาร์ท ในกรณีนี้ k8s เสนอวิธีที่ลึกกว่า 2 วิธีในการระบุปัญหาเกี่ยวกับพ็อด: livenessProbe и การสอบสวนความพร้อม.

LivenessProbe

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

  • ตั้งค่าคำขอ HTTP ไปยังพ็อด การตอบกลับจะต้องมีรหัสการตอบกลับ HTTP ในช่วงตั้งแต่ 200 ถึง 399 ดังนั้น รหัส 5xx และ 4xx จะส่งสัญญาณว่าพ็อดกำลังมีปัญหา แม้ว่ากระบวนการกำลังทำงานอยู่ก็ตาม
  • หากต้องการทดสอบพ็อดด้วยบริการที่ไม่ใช่ HTTP (เช่น เซิร์ฟเวอร์อีเมล Postfix) คุณต้องสร้างการเชื่อมต่อ TCP
  • ดำเนินการคำสั่งที่กำหนดเองสำหรับพ็อด (ภายใน) การตรวจสอบจะถือว่าสำเร็จหากรหัสคำสั่งเสร็จสิ้นเป็น 0

ตัวอย่างวิธีการทำงานนี้ คำนิยามพ็อดถัดไปประกอบด้วยแอปพลิเคชัน NodeJS ที่ส่งข้อผิดพลาด 500 ในคำขอ HTTP เพื่อให้แน่ใจว่าคอนเทนเนอร์รีสตาร์ทเมื่อได้รับข้อผิดพลาดดังกล่าว เราใช้พารามิเตอร์ livenessProbe:

apiVersion: v1
kind: Pod
metadata:
 name: node500
spec:
 containers:
   - image: magalix/node500
     name: node500
     ports:
       - containerPort: 3000
         protocol: TCP
     livenessProbe:
       httpGet:
         path: /
         port: 3000
       initialDelaySeconds: 5

นี่ไม่แตกต่างจากคำจำกัดความของพ็อดอื่น ๆ แต่เรากำลังเพิ่มออบเจ็กต์ .spec.containers.livenessProbe. พารามิเตอร์ httpGet ยอมรับเส้นทางที่คำขอ HTTP GET ถูกส่งไป (ในตัวอย่างของเรา นี่คือ /แต่ในสถานการณ์การต่อสู้อาจมีบางอย่างเช่นนี้ /api/v1/status). livenessProbe อื่นยอมรับพารามิเตอร์ initialDelaySecondsซึ่งสั่งให้การดำเนินการตรวจสอบรอตามจำนวนวินาทีที่ระบุ จำเป็นต้องมีการหน่วงเวลาเนื่องจากคอนเทนเนอร์ต้องใช้เวลาในการเริ่มต้น และเมื่อรีสตาร์ทคอนเทนเนอร์จะใช้งานไม่ได้เป็นระยะเวลาหนึ่ง

หากต้องการใช้การตั้งค่านี้กับคลัสเตอร์ ให้ใช้:

kubectl apply -f pod.yaml

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

kubectl describe pods node500

ในตอนท้ายของผลลัพธ์ ให้ค้นหา นั่นคือสิ่งที่.

อย่างที่คุณเห็น livenessProbe เริ่มต้นคำขอ HTTP GET คอนเทนเนอร์สร้างข้อผิดพลาด 500 (ซึ่งเป็นสิ่งที่ถูกตั้งโปรแกรมให้ทำ) และ kubelet จะรีสตาร์ท

หากคุณสงสัยว่าแอปพลิเคชัน NideJS ได้รับการตั้งโปรแกรมอย่างไร นี่คือ app.js และ Dockerfile ที่ใช้:

แอพ.js

var http = require('http');

var server = http.createServer(function(req, res) {
    res.writeHead(500, { "Content-type": "text/plain" });
    res.end("We have run into an errorn");
});

server.listen(3000, function() {
    console.log('Server is running at 3000')
})

ไฟล์นักเทียบท่า

FROM node
COPY app.js /
EXPOSE 3000
ENTRYPOINT [ "node","/app.js" ]

สิ่งสำคัญที่ควรทราบคือ livenessProbe จะรีสตาร์ทคอนเทนเนอร์หากล้มเหลวเท่านั้น หากการรีสตาร์ทไม่แก้ไขข้อผิดพลาดที่ทำให้คอนเทนเนอร์ไม่ทำงาน kubelet จะไม่สามารถดำเนินการแก้ไขปัญหาได้

การสอบสวนความพร้อม

readinessProbe ทำงานคล้ายกับ livenessProbes (คำขอ GET, การสื่อสาร TCP และการดำเนินการคำสั่ง) ยกเว้นการดำเนินการแก้ไขปัญหา คอนเทนเนอร์ที่ตรวจพบความล้มเหลวจะไม่รีสตาร์ท แต่ถูกแยกออกจากการรับส่งข้อมูลขาเข้า ลองนึกภาพว่าหนึ่งในคอนเทนเนอร์กำลังคำนวณจำนวนมากหรืออยู่ภายใต้ภาระงานหนัก ส่งผลให้เวลาตอบสนองเพิ่มขึ้น ในกรณีของ livenessProbe การตรวจสอบความพร้อมใช้งานของการตอบสนองจะถูกทริกเกอร์ (ผ่านพารามิเตอร์การตรวจสอบ timeoutSeconds) หลังจากนั้น kubelet จะรีสตาร์ทคอนเทนเนอร์ เมื่อเริ่มต้น คอนเทนเนอร์จะเริ่มดำเนินงานที่ใช้ทรัพยากรสูงและรีสตาร์ทอีกครั้ง นี่อาจเป็นสิ่งสำคัญสำหรับแอปพลิเคชันที่ต้องการความเร็วในการตอบสนอง ตัวอย่างเช่น รถยนต์ขณะอยู่บนถนนกำลังรอการตอบกลับจากเซิร์ฟเวอร์ การตอบกลับล่าช้า และรถก็เกิดอุบัติเหตุ

มาเขียนคำจำกัดความ redinessProbe ที่จะตั้งเวลาตอบสนองคำขอ GET ไม่เกินสองวินาที และแอปพลิเคชันจะตอบสนองต่อคำขอ GET หลังจากผ่านไป 5 วินาที ไฟล์ pod.yaml ควรมีลักษณะดังนี้:

apiVersion: v1
kind: Pod
metadata:
 name: nodedelayed
spec:
 containers:
   - image: afakharany/node_delayed
     name: nodedelayed
     ports:
       - containerPort: 3000
         protocol: TCP
     readinessProbe:
       httpGet:
         path: /
         port: 3000
       timeoutSeconds: 2

มาปรับใช้พ็อดด้วย kubectl:

kubectl apply -f pod.yaml

รอสองสามวินาทีแล้วดูว่า readinessProbe ทำงานอย่างไร:

kubectl describe pods nodedelayed

ในตอนท้ายของผลลัพธ์ คุณจะเห็นว่าเหตุการณ์บางอย่างคล้ายกัน อันนี้.

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

โปรดทราบว่าเมื่อพ็อดถูกถ่ายออกแล้ว kubectl จะกำหนดเส้นทางคำขอไปที่พ็อดอีกครั้ง: การตอบสนองต่อคำขอ GET จะไม่ล่าช้าอีกต่อไป

เพื่อการเปรียบเทียบ ด้านล่างนี้คือไฟล์ app.js ที่ถูกแก้ไข:

var http = require('http');

var server = http.createServer(function(req, res) {
   const sleep = (milliseconds) => {
       return new Promise(resolve => setTimeout(resolve, milliseconds))
   }
   sleep(5000).then(() => {
       res.writeHead(200, { "Content-type": "text/plain" });
       res.end("Hellon");
   })
});

server.listen(3000, function() {
   console.log('Server is running at 3000')
})

TL; DR
ก่อนที่จะมีแอปพลิเคชันบนระบบคลาวด์ บันทึกเป็นวิธีการหลักในการตรวจสอบและตรวจสอบความสมบูรณ์ของแอปพลิเคชัน อย่างไรก็ตามไม่มีหนทางดำเนินการแก้ไขใดๆ บันทึกยังคงมีประโยชน์ในปัจจุบัน โดยจะต้องรวบรวมและส่งไปยังระบบรวบรวมบันทึกเพื่อวิเคราะห์สถานการณ์ฉุกเฉินและการตัดสินใจ [ทั้งหมดนี้สามารถทำได้โดยไม่ต้องใช้แอปพลิเคชันบนคลาวด์ที่ใช้ monit แต่ด้วย k8s มันง่ายกว่ามาก :) – หมายเหตุจากบรรณาธิการ ]

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

Kubernetes มีการตรวจสอบประสิทธิภาพการทำงาน 2 ประเภทตามค่าเริ่มต้น ได้แก่ readinessProbe และ livenessProbe ทั้งสองใช้การตรวจสอบประเภทเดียวกัน (คำขอ HTTP GET, การสื่อสาร TCP และการดำเนินการคำสั่ง) พวกเขาต่างกันในการตัดสินใจเพื่อตอบสนองต่อปัญหาในพ็อด livenessProbe รีสตาร์ทคอนเทนเนอร์ด้วยความหวังว่าข้อผิดพลาดจะไม่เกิดขึ้นอีก และ readinessProbe จะแยกพ็อดออกจากการรับส่งข้อมูลขาเข้าจนกว่าสาเหตุของปัญหาจะได้รับการแก้ไข

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

ที่มา: will.com

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