Βέλτιστες πρακτικές για τα δοχεία Kubernetes: Έλεγχοι υγείας

Βέλτιστες πρακτικές για τα δοχεία Kubernetes: Έλεγχοι υγείας

TL? DR

  • Για να επιτευχθεί υψηλή παρατηρησιμότητα δοχείων και μικροϋπηρεσιών, τα κούτσουρα και οι κύριες μετρήσεις δεν αρκούν.
  • Για ταχύτερη ανάκτηση και αυξημένη ανθεκτικότητα, οι εφαρμογές θα πρέπει να εφαρμόζουν την αρχή της υψηλής παρατηρησιμότητας (HOP).
  • Σε επίπεδο εφαρμογής, το NOP απαιτεί: σωστή καταγραφή, στενή παρακολούθηση, ελέγχους υγιεινής και ανίχνευση απόδοσης/μετάβασης.
  • Χρησιμοποιήστε τις επιταγές ως στοιχείο του NOR ReadinessProbe и livenessProbe Kubernetes.

Τι είναι το πρότυπο ελέγχου υγείας;

Όταν σχεδιάζετε μια κρίσιμη για την αποστολή και εξαιρετικά διαθέσιμη εφαρμογή, είναι πολύ σημαντικό να σκεφτείτε μια πτυχή όπως η ανοχή σφαλμάτων. Μια εφαρμογή θεωρείται ανεκτική σε σφάλματα εάν επανέλθει γρήγορα από την αστοχία. Μια τυπική εφαρμογή cloud χρησιμοποιεί μια αρχιτεκτονική microservices - όπου κάθε στοιχείο τοποθετείται σε ξεχωριστό δοχείο. Και για να βεβαιωθείτε ότι η εφαρμογή στα k8s είναι ιδιαίτερα διαθέσιμη όταν σχεδιάζετε ένα σύμπλεγμα, πρέπει να ακολουθήσετε ορισμένα μοτίβα. Μεταξύ αυτών είναι το Πρότυπο Ελέγχου Υγείας. Καθορίζει πώς η εφαρμογή επικοινωνεί στα k8s ότι είναι υγιής. Δεν πρόκειται μόνο για πληροφορίες σχετικά με το εάν το pod εκτελείται, αλλά και για το πώς λαμβάνει και ανταποκρίνεται σε αιτήματα. Όσο περισσότερα γνωρίζει η Kubernetes για την υγεία του pod, τόσο πιο έξυπνες αποφάσεις παίρνει σχετικά με τη δρομολόγηση της κυκλοφορίας και την εξισορρόπηση φορτίου. Έτσι, η αρχή της υψηλής παρατηρησιμότητας επιτρέπει στην εφαρμογή να ανταποκρίνεται σε αιτήματα έγκαιρα.

Αρχή υψηλής παρατηρησιμότητας (HOP)

Η αρχή της υψηλής παρατηρησιμότητας είναι μία από τις αρχές για το σχεδιασμό εφαρμογών σε εμπορευματοκιβώτια. Σε μια αρχιτεκτονική μικροϋπηρεσιών, οι υπηρεσίες δεν ενδιαφέρονται για τον τρόπο επεξεργασίας του αιτήματός τους (και σωστά), αλλά αυτό που έχει σημασία είναι πώς λαμβάνουν απαντήσεις από τις υπηρεσίες που λαμβάνουν. Για παράδειγμα, για τον έλεγχο ταυτότητας ενός χρήστη, ένα κοντέινερ στέλνει ένα αίτημα HTTP σε ένα άλλο, αναμένοντας μια απάντηση σε μια συγκεκριμένη μορφή - αυτό είναι όλο. Το PythonJS μπορεί επίσης να επεξεργαστεί το αίτημα και το Python Flask μπορεί να ανταποκριθεί. Τα δοχεία είναι σαν μαύρα κουτιά με κρυμμένα περιεχόμενα μεταξύ τους. Ωστόσο, η αρχή NOP απαιτεί από κάθε υπηρεσία να εκθέτει πολλά τελικά σημεία API που υποδεικνύουν πόσο υγιές είναι, καθώς και την ετοιμότητά της και την κατάσταση ανοχής σφαλμάτων. Η Kubernetes ζητά αυτούς τους δείκτες για να σκεφτεί τα επόμενα βήματα για τη δρομολόγηση και την εξισορρόπηση φορτίου.

Μια καλά σχεδιασμένη εφαρμογή cloud καταγράφει τα κύρια συμβάντα της χρησιμοποιώντας τις τυπικές ροές I/O STDERR και STDOUT. Στη συνέχεια ακολουθεί μια βοηθητική υπηρεσία, για παράδειγμα filebeat, logstash ή fluentd, που παρέχει αρχεία καταγραφής σε ένα κεντρικό σύστημα παρακολούθησης (για παράδειγμα Prometheus) και ένα σύστημα συλλογής αρχείων καταγραφής (σουίτα λογισμικού ELK). Το παρακάτω διάγραμμα δείχνει πώς λειτουργεί μια εφαρμογή cloud σύμφωνα με το Health Test Pattern και την Αρχή High Observability Principle.

Βέλτιστες πρακτικές για τα δοχεία Kubernetes: Έλεγχοι υγείας

Πώς να εφαρμόσετε το Μοτίβο Ελέγχου Υγείας στο Kubernetes;

Εκτός συσκευασίας, το k8s παρακολουθεί την κατάσταση των pod χρησιμοποιώντας έναν από τους ελεγκτές (Ανάπτυξη, ReplicaSets, DaemonSets, StatefulSets κλπ., κλπ.). Έχοντας ανακαλύψει ότι το pod έχει πέσει για κάποιο λόγο, ο ελεγκτής προσπαθεί να το επανεκκινήσει ή να το μετακινήσει σε άλλο κόμβο. Ωστόσο, ένα pod μπορεί να αναφέρει ότι είναι σε λειτουργία, αλλά το ίδιο δεν λειτουργεί. Ας δώσουμε ένα παράδειγμα: η εφαρμογή σας χρησιμοποιεί τον Apache ως διακομιστή ιστού, εγκαταστήσατε το στοιχείο σε πολλά pod του συμπλέγματος. Δεδομένου ότι η βιβλιοθήκη δεν έχει ρυθμιστεί σωστά, όλα τα αιτήματα προς την εφαρμογή απαντούν με κωδικό 500 (εσωτερικό σφάλμα διακομιστή). Κατά τον έλεγχο της παράδοσης, ο έλεγχος της κατάστασης των pods δίνει ένα επιτυχημένο αποτέλεσμα, αλλά οι πελάτες σκέφτονται διαφορετικά. Θα περιγράψουμε αυτήν την ανεπιθύμητη κατάσταση ως εξής:

Βέλτιστες πρακτικές για τα δοχεία Kubernetes: Έλεγχοι υγείας

Στο παράδειγμά μας, το k8s κάνει έλεγχος λειτουργικότητας. Σε αυτόν τον τύπο επαλήθευσης, το kubelet ελέγχει συνεχώς την κατάσταση της διαδικασίας στο κοντέινερ. Μόλις καταλάβει ότι η διαδικασία έχει σταματήσει, θα την επανεκκινήσει. Εάν το σφάλμα μπορεί να επιλυθεί με απλή επανεκκίνηση της εφαρμογής και το πρόγραμμα έχει σχεδιαστεί για να τερματίζεται σε οποιοδήποτε σφάλμα, τότε ο έλεγχος υγείας της διαδικασίας είναι το μόνο που χρειάζεστε για να ακολουθήσετε το NOP και το πρότυπο δοκιμής υγείας. Το μόνο κρίμα είναι ότι δεν εξαλείφονται όλα τα σφάλματα με επανεκκίνηση. Σε αυτήν την περίπτωση, το k8s προσφέρει 2 βαθύτερους τρόπους για τον εντοπισμό προβλημάτων με το pod: livenessProbe и ReadinessProbe.

LivenessProbe

Κατά τη διάρκεια του livenessProbe Το kubelet εκτελεί 3 τύπους ελέγχων: όχι μόνο καθορίζει εάν το pod εκτελείται, αλλά και εάν είναι έτοιμο να λάβει και να ανταποκριθεί επαρκώς σε αιτήματα:

  • Ρυθμίστε ένα αίτημα HTTP στο pod. Η απόκριση πρέπει να περιέχει έναν κωδικό απόκρισης HTTP στην περιοχή από 200 έως 399. Έτσι, οι κωδικοί 5xx και 4xx σηματοδοτούν ότι το pod αντιμετωπίζει προβλήματα, παρόλο που η διαδικασία εκτελείται.
  • Για να δοκιμάσετε pods με υπηρεσίες εκτός HTTP (για παράδειγμα, τον διακομιστή αλληλογραφίας Postfix), πρέπει να δημιουργήσετε μια σύνδεση TCP.
  • Εκτελέστε μια αυθαίρετη εντολή για ένα pod (εσωτερικά). Ο έλεγχος θεωρείται επιτυχής εάν ο κωδικός ολοκλήρωσης της εντολής είναι 0.

Ένα παράδειγμα για το πώς λειτουργεί αυτό. Ο επόμενος ορισμός pod περιέχει μια εφαρμογή 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

Αυτός δεν διαφέρει από οποιονδήποτε άλλο ορισμό pod, αλλά προσθέτουμε ένα αντικείμενο .spec.containers.livenessProbe. Παράμετρος httpGet αποδέχεται τη διαδρομή στην οποία αποστέλλεται το αίτημα HTTP GET (στο παράδειγμά μας αυτό είναι /, αλλά σε σενάρια μάχης μπορεί να υπάρχει κάτι σαν /api/v1/status). Ένα άλλο livenessProbe δέχεται μια παράμετρο initialDelaySeconds, το οποίο δίνει εντολή στη λειτουργία επαλήθευσης να περιμένει έναν καθορισμένο αριθμό δευτερολέπτων. Η καθυστέρηση είναι απαραίτητη επειδή το κοντέινερ χρειάζεται χρόνο για να ξεκινήσει και όταν επανεκκινηθεί θα είναι μη διαθέσιμο για κάποιο χρονικό διάστημα.

Για να εφαρμόσετε αυτήν τη ρύθμιση σε ένα σύμπλεγμα, χρησιμοποιήστε:

kubectl apply -f pod.yaml

Μετά από μερικά δευτερόλεπτα, μπορείτε να ελέγξετε τα περιεχόμενα του pod χρησιμοποιώντας την ακόλουθη εντολή:

kubectl describe pods node500

Στο τέλος της εξόδου, βρείτε αυτό είναι ό, τι.

Όπως μπορείτε να δείτε, το livenessProbe ξεκίνησε ένα αίτημα HTTP GET, το κοντέινερ δημιούργησε ένα σφάλμα 500 (αυτό που είχε προγραμματιστεί να κάνει) και το kubelet το επανεκκίνησε.

Αν αναρωτιέστε πώς προγραμματίστηκε η εφαρμογή NideJS, εδώ είναι το app.js και το Dockerfile που χρησιμοποιήθηκαν:

app.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')
})

Dockerfile

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

Είναι σημαντικό να σημειώσετε αυτό: το livenessProbe θα επανεκκινήσει το δοχείο μόνο εάν αποτύχει. Εάν μια επανεκκίνηση δεν διορθώσει το σφάλμα που εμποδίζει τη λειτουργία του κοντέινερ, το kubelet δεν θα μπορεί να προβεί σε ενέργειες για τη διόρθωση του προβλήματος.

ReadinessProbe

Το 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

Ας αναπτύξουμε ένα pod με kubectl:

kubectl apply -f pod.yaml

Ας περιμένουμε μερικά δευτερόλεπτα και μετά δούμε πώς λειτούργησε το ReadinessProbe:

kubectl describe pods nodedelayed

Στο τέλος της εξόδου μπορείτε να δείτε ότι μερικά από τα συμβάντα είναι παρόμοια αυτό.

Όπως μπορείτε να δείτε, το kubectl δεν έκανε επανεκκίνηση του pod όταν ο χρόνος ελέγχου ξεπέρασε τα 2 δευτερόλεπτα. Αντίθετα, ακύρωσε το αίτημα. Οι εισερχόμενες επικοινωνίες ανακατευθύνονται σε άλλες ομάδες εργασίας.

Λάβετε υπόψη ότι τώρα που το pod έχει εκφορτωθεί, το 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
Πριν από την εμφάνιση των εφαρμογών cloud, τα αρχεία καταγραφής ήταν το κύριο μέσο παρακολούθησης και ελέγχου της υγείας των εφαρμογών. Ωστόσο, δεν υπήρχε κανένα μέσο για να ληφθούν διορθωτικά μέτρα. Τα αρχεία καταγραφής εξακολουθούν να είναι χρήσιμα σήμερα· πρέπει να συλλέγονται και να αποστέλλονται σε ένα σύστημα συλλογής αρχείων καταγραφής για την ανάλυση καταστάσεων έκτακτης ανάγκης και τη λήψη αποφάσεων. [Όλα αυτά θα μπορούσαν να γίνουν χωρίς εφαρμογές cloud χρησιμοποιώντας monit, για παράδειγμα, αλλά με το k8 έγινε πολύ πιο εύκολο :) – σημείωση του συντάκτη. ]

Σήμερα, οι διορθώσεις πρέπει να γίνονται σχεδόν σε πραγματικό χρόνο, επομένως οι εφαρμογές δεν χρειάζεται πλέον να είναι μαύρα κουτιά. Όχι, θα πρέπει να εμφανίζουν τελικά σημεία που επιτρέπουν στα συστήματα παρακολούθησης να αναζητούν και να συλλέγουν πολύτιμα δεδομένα σχετικά με την κατάσταση των διεργασιών, ώστε να μπορούν να ανταποκρίνονται άμεσα εάν είναι απαραίτητο. Αυτό ονομάζεται μοτίβο σχεδίασης δοκιμής απόδοσης, το οποίο ακολουθεί την αρχή της υψηλής παρατηρησιμότητας (HOP).

Η Kubernetes προσφέρει 2 τύπους ελέγχων υγείας από προεπιλογή: ReadinessProbe και livenessProbe. Και οι δύο χρησιμοποιούν τους ίδιους τύπους ελέγχων (αιτήματα HTTP GET, επικοινωνίες TCP και εκτέλεση εντολών). Διαφέρουν ως προς τις αποφάσεις που λαμβάνουν ως απάντηση σε προβλήματα στα λοβό. Το livenessProbe επανεκκινεί το κοντέινερ με την ελπίδα ότι το σφάλμα δεν θα συμβεί ξανά και το ReadinessProbe απομονώνει το pod από την εισερχόμενη κυκλοφορία μέχρι να επιλυθεί η αιτία του προβλήματος.

Ο σωστός σχεδιασμός της εφαρμογής θα πρέπει να περιλαμβάνει και τους δύο τύπους ελέγχου και να διασφαλίζει ότι συλλέγουν αρκετά δεδομένα, ειδικά όταν γίνεται εξαίρεση. Θα πρέπει επίσης να εμφανίζει τα απαραίτητα τελικά σημεία API που παρέχουν στο σύστημα παρακολούθησης (Prometheus) σημαντικές μετρήσεις υγείας.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο