Αποστολή Helm: βιομηχανοποίηση πολλαπλών περιβάλλοντος ανάπτυξης

15 λεπτά

Έργο 13 — Helm στο Kubernetes · Επίπεδο ενδιάμεσο → προχωρημένο · Εκτιμώμενη διάρκεια: 4 έως 6 ώρες

Ξεκινάτε από μια εφαρμογή αποτελούμενη από δύο υπηρεσίες Python (ένα οπτικό portail και μια api backend), και θα την αναπτύξετε τρεις φορές δίπλα-δίπλα — σε DEV (μπλε), STAGING (πορτοκαλί), PROD (πράσινο) — με ένα μόνο Chart Helm και τρία αρχεία τιμών. Στο τέλος, θα κάνετε ένα helm upgrade έπειτα ένα helm rollback, και θα επισκευάσετε τρία πρότυπα γεμάτα πραγματικά σφάλματα που συναντώνται στην επιχείρηση.


Πίνακας περιεχομένων


Το πλαίσιο

Εργάζεστε σε μια ομάδα όπου κάθε νέα έκδοση μιας εφαρμογής πρέπει να περάσει από τρία περιβάλλοντα:

  • DEV — αμμοδόχος των προγραμματιστών, αναλώσιμα δεδομένα, ένα μόνο αντίγραφο.
  • STAGING — προ-παραγωγή, δεδομένα δοκιμής, δύο αντίγραφα για επικύρωση της κλιμάκωσης.
  • PROD — παραγωγή, πραγματικά δεδομένα, τουλάχιστον τρία αντίγραφα, κανένα downtime ανεκτό.

Σήμερα, η ομάδα αντιγράφει-επικολλά τα ίδια μανιφέστα YAML για κάθε περιβάλλον αλλάζοντας χειροκίνητα τις διαφορετικές τιμές. Αποτέλεσμα: τα αρχεία αποκλίνουν, μια διόρθωση που εφαρμόστηκε στο dev δεν βρίσκεται στην παραγωγή, και μια ανάπτυξη απαιτεί μισή ημέρα.

Η αποστολή σας: να εκβιομηχανίσετε όλα αυτά με Helm. Ένα μόνο Chart, τρία αρχεία τιμών, μία εντολή ανά περιβάλλον. Θα αποδείξετε ότι λειτουργεί εμφανίζοντας τρεις πίνακες ελέγχου δίπλα-δίπλα στον περιηγητή σας — καθένας με το δικό του χρώμα, τον δικό του αριθμό Pods, και το δικό του μήνυμα.


Ουσιώδεις έννοιες πριν ξεκινήσετε

Αυτό το έγγραφο είναι αυτάρκες. Δεν χρειάζεστε καμία εξωτερική αναφορά για να το ολοκληρώσετε.

1. Ο ρόλος του Helm σε μία πρόταση

Το Helm παράγει μανιφέστα Kubernetes από πρότυπα και μεταβλητές. Εκεί όπου το kubectl apply παίρνει ένα στατικό YAML, το Helm παίρνει ένα πρότυπο YAML και ένα αρχείο τιμών, παράγει το τελικό YAML, έπειτα το εφαρμόζει ως εκδοχημένη μονάδα που ονομάζουμε release.

2. Ανατομία ενός Chart

mon-chart/
├── Chart.yaml            # μεταδεδομένα (όνομα, έκδοση)
├── values.yaml           # τιμές ΑΠΟ ΠΡΟΕΠΙΛΟΓΗ
└── templates/            # πρότυπα YAML
    ├── deployment.yaml
    ├── service.yaml
    └── _helpers.tpl      # κοινές συναρτήσεις προτύπου (όνομα με πρόθεμα _)

Τα αρχεία των οποίων το όνομα αρχίζει με _ δεν παράγουν κανένα μανιφέστο: χρησιμεύουν στον ορισμό επαναχρησιμοποιήσιμων «helpers» μέσω {{ include "nom" . }}.

3. Η σύνταξη των προτύπων (Go template)

ΓράφεταιΑποδίδεται
{{ .Values.portail.replicas }}Η τιμή που ορίζεται στο values.yaml
{{ .Release.Name }}Το όνομα που περάσατε στο helm install (π.χ. hedge-dev)
{{ .Chart.Name }}Το όνομα του chart (ορισμένο στο Chart.yaml)
{{ .Chart.AppVersion }}Η έκδοση εφαρμογής (ορισμένη στο Chart.yaml)
{{ include "hedge.labels" . }}Κλήση ενός helper ορισμένου στο _helpers.tpl
{{- ... -}}Το - αφαιρεί τα κενά πριν/μετά την απόδοση
{{ .Values.env | quote }}Προσθέτει εισαγωγικά γύρω από την τιμή
{{ .Values.replicas | default 1 }}Χρησιμοποιεί 1 αν η τιμή δεν είναι ορισμένη

4. Οι 5 εντολές Helm που θα χρησιμοποιήσετε

powershell
helm lint ./chart                                              # επαλήθευση σύνταξης
helm template <release> ./chart -f values-<env>.yaml           # ΣΤΕΓΝΗ απόδοση (καμία ανάπτυξη)
helm install <release> ./chart -f values-<env>.yaml -n <ns>    # πραγματική ανάπτυξη
helm upgrade <release> ./chart -f values-<env>.yaml -n <ns>    # σταδιακή τροποποίηση
helm rollback <release> <revision> -n <ns>                     # επιστροφή πίσω

5. Η λέξη-κλειδί «release»

Μια release είναι μια εγκατάσταση ενός chart. Το ίδιο chart μπορεί να εγκατασταθεί πολλές φορές, καθένα με διαφορετικό όνομα release (hedge-dev, hedge-staging, hedge-prod) — αυτό είναι το θεμέλιο του πολλαπλού περιβάλλοντος.

Το {{ .Release.Name }} αλλάζει σε κάθε install, το {{ .Chart.Name }} μένει ίδιο. Κρατήστε αυτή την αντίθεση: είναι κεντρική.

6. Ο χρυσός κανόνας του αμετάβλητου selector

Το πεδίο spec.selector.matchLabels ενός Deployment είναι σταθερό μία για πάντα στη δημιουργία. Αν το πρότυπό σας βάλει σε αυτό το πεδίο μια τιμή που μπορεί να αλλάξει (όπως μια έκδοση, ένα περιβάλλον, μια ημερομηνία), το πρώτο helm install θα πετύχει, αλλά το πρώτο helm upgrade θα αποτύχει με:

spec.selector: Invalid value: ...: field is immutable

Κανόνας να χαραχτεί στην πέτρα: στο matchLabels, βάλτε μόνο πράγματα που δεν θα αλλάξουν ΠΟΤΕ για αυτή την παρουσία — τυπικά name, instance, component.


Η στοχευμένη αρχιτεκτονική: DEV / STAGING / PROD

Θα αναπτύξετε το ίδιο chart σε τρεις διακριτούς χώρους ονομάτων, καθένας με τις παραμέτρους του:

ΠαράμετροςDEVSTAGINGPROD
Namespacehedge-devhedge-staginghedge-prod
Release namehedge-devhedge-staginghedge-prod
Χρώμα πανόμπλε #2563ebπορτοκαλί #ea580cπράσινο #16a34a
Μήνυμα« Περιβάλλον ανάπτυξης… »« Προ-παραγωγή — μόνο δεδομένα δοκιμής »« Παραγωγή — κάθε ενέργεια έχει πραγματικό αντίκτυπο »
Αντίγραφα portail123
Αντίγραφα api123
Εκτεθειμένη θύρα (NodePort)301303013130132
URL δοκιμήςhttp://localhost:30130http://localhost:30131http://localhost:30132

Στο τέλος του εργαστηρίου, ανοίγετε τρεις καρτέλες δίπλα-δίπλα και βλέπετε τρεις πίνακες ελέγχου χρωματισμένους διαφορετικά, καθένας να εμφανίζει το περιβάλλον του, την έκδοσή του, τα Pods του, και την κατάσταση του backend του.


Διάταξη των αρχείων

Ξεκινάτε από την ακόλουθη δενδροδομή — το ΠΑΡΑΡΤΗΜΑ παρέχει το ακριβές περιεχόμενο κάθε αρχείου:

projet13-kubernetes-helm-tp/
├── 00-ENONCE.md                              <- αυτό το έγγραφο

├── apps/                                     <- Ο ΚΩΔΙΚΑΣ (ΠΑΡΑΡΤΗΜΑ A) — ΝΑ ΜΗΝ ΤΡΟΠΟΠΟΙΗΘΕΙ
│   ├── portail/
│   │   ├── app.py
│   │   ├── requirements.txt
│   │   └── Dockerfile
│   └── api/
│       ├── app.py
│       ├── requirements.txt
│       └── Dockerfile

├── chart/                                    <- ΤΟ CHART ΠΡΟΣ ΣΥΜΠΛΗΡΩΣΗ
│   ├── Chart.yaml                            <- σκελετός (ΠΑΡΑΡΤΗΜΑ B)
│   ├── values.yaml                           <- προεπιλεγμένες τιμές (ΠΑΡΑΡΤΗΜΑ B)
│   │
│   ├── environments/                         <- ΣΕΙΡΑ ΣΑΣ
│   │   ├── values-dev.yaml                   <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   ├── values-staging.yaml               <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   └── values-prod.yaml                  <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │
│   ├── templates/                            <- ΣΕΙΡΑ ΣΑΣ
│   │   ├── _helpers.tpl                      <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   ├── portail-deployment.yaml           <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   ├── portail-service.yaml              <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   ├── api-deployment.yaml               <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │   └── api-service.yaml                  <- σκελετός TODO (ΠΑΡΑΡΤΗΜΑ B)
│   │
│   └── casses/                               <- ΠΑΡΕΧΟΝΤΑΙ αλλά ΕΛΑΤΤΩΜΑΤΙΚΑ (ΠΑΡΑΡΤΗΜΑ C)
│       ├── casse-1-configmap.yaml
│       ├── casse-2-worker-deployment.yaml
│       └── casse-3-cache-deployment.yaml

├── outils/
│   └── valider.ps1                           <- ΠΑΡΕΧΕΤΑΙ (ΠΑΡΑΡΤΗΜΑ D)

└── RAPPORT.md                                <- ΝΑ ΣΥΝΤΑΧΘΕΙ από εσάς

Κρίσιμο σημείο: τα αρχεία του chart/casses/ δεν βρίσκονται στο chart/templates/. Το Helm λοιπόν δεν τα φορτώνει αυτόματα. Η αποστολή 6 θα σας ζητήσει να τα αντιγράψετε ένα-ένα στο templates/ για να παρατηρήσετε το σφάλμα, έπειτα να τα επισκευάσετε πριν τα κρατήσετε.


Οι κανόνες του παιχνιδιού

  1. Απόλυτη απαγόρευση τροποποίησης του φακέλου apps/. Ο κώδικας εφαρμογής είναι ήδη γραμμένος — είστε ο DevOps, όχι ο προγραμματιστής.
  2. Τροποποιείτε μόνο τα αρχεία του φακέλου chart/.
  3. Καμία διαμόρφωση περιβάλλοντος κωδικοποιημένη στα σκληρά σε πρότυπο: replicas, nodePort, χρώμα, μήνυμα, περιβάλλον — όλα πρέπει να προέρχονται από ένα .Values.*.
  4. Τα 3 αρχεία values-<env>.yaml πρέπει να διαφέρουν μόνο ως προς τις τιμές που διακρίνουν DEV, STAGING και PROD. Ένα αρχείο values-prod.yaml που επαναορίζει άσκοπα το image.repository ή το service.targetPort είναι σφάλμα — αυτά προέρχονται από το values.yaml.
  5. Εργάζεστε στο ενσωματωμένο Kubernetes του Docker Desktop.

Προετοιμασία

Προαπαιτούμενα — να επαληθευτούν μία μόνο φορά

  1. Το Docker Desktop είναι εκκινημένο και το Kubernetes είναι ενεργό (Settings → Kubernetes → Enable Kubernetes).
  2. Το Docker Desktop διαθέτει τουλάχιστον 4 GB RAM δεσμευμένα (Settings → Resources → Memory ≥ 4 GB). Αυτό το εργαστήριο τρέχει 12 Pods ταυτόχρονα (1+1 + 2+2 + 3+3).
  3. Το Helm είναι εγκατεστημένο:
    powershell
    helm version --short           # πρέπει να εμφανίζει v3.x ή v4.x
    Αλλιώς: winget install Helm.Helmchoco install kubernetes-helm).
  4. Βρίσκεστε στο σωστό σύμπλεγμα:
    powershell
    kubectl config use-context docker-desktop
    kubectl get nodes              # docker-desktop   Ready

Κατασκευή των εικόνων

Το chart αναφέρεται σε δύο τοπικές εικόνες που πρέπει να κατασκευάσετε μία μόνο φορά:

powershell
docker build -t hedge-portail:1.0 .\apps\portail
docker build -t hedge-api:1.0     .\apps\api

docker images | Select-String "^hedge"      # πρέπει να εμφανίζει τις 2 εικόνες

Υπενθύμιση: το Docker Desktop μοιράζεται τον δαίμονά του με το Kubernetes· κανένα βήμα «φόρτωσης» δεν είναι απαραίτητο (σε αντίθεση με το kind ή το minikube).


Οι αποστολές

Αποστολή 1 — Να ζωντανέψετε ένα ελάχιστο Chart (10 βαθμοί)

Συμπληρώστε το chart/Chart.yaml (όνομα, apiVersion, type, version, appVersion). Επαληθεύστε έπειτα:

powershell
helm lint .\chart
# πρέπει να εμφανίζει : 1 chart(s) linted, 0 chart(s) failed

Αναμενόμενο: ένα Chart που περνά το lint χωρίς σφάλμα.


Αποστολή 2 — Προτυποποίηση portail και api (20 βαθμοί)

Συμπληρώστε τα 4 αρχεία του chart/templates/:

  • portail-deployment.yaml — ένα Deployment που χρησιμοποιεί .Values.portail.replicas, .Values.portail.image.*, και εγχέει τις μεταβλητές περιβάλλοντος ENVIRONMENT, APP_VERSION, THEME_COLOR, BANNIERE_MESSAGE, BACKEND_URL, REPLICAS_INFO.
  • portail-service.yaml — ένα Service NodePort που δείχνει στα Pods του portail.
  • api-deployment.yaml — ένα Deployment για την api (μεταβλητές ENVIRONMENT, APP_VERSION).
  • api-service.yaml — ένα Service ClusterIP.

Κρίσιμο σημείο: η μεταβλητή BACKEND_URL του portail πρέπει να περιέχει το όνομα του Service api κατασκευασμένο με {{ .Release.Name }} (π.χ. http://hedge-dev-api), όχι ένα όνομα στα σκληρά.

Επικύρωση:

powershell
helm template check .\chart -f .\chart\environments\values-dev.yaml
# πρέπει να εμφανίζει 2 Deployments + 2 Services, όλα με πρόθεμα "check-"

Αποστολή 3 — Να γράψετε καθαρούς helpers (15 βαθμοί)

Συμπληρώστε το chart/templates/_helpers.tpl με τρεις helpers:

  1. hedge.fullname — επιστρέφει {{ .Release.Name }}-<composant> (π.χ. hedge-dev-portail).
  2. hedge.labels — επιστρέφει τις τυπικές ετικέτες:
    • app.kubernetes.io/name
    • app.kubernetes.io/instance
    • app.kubernetes.io/component
    • app.kubernetes.io/managed-by
    • app.kubernetes.io/version
    • helm.sh/chart
    • hedge/environment
  3. hedge.selectorLabels — επιστρέφει μόνο name, instance, component (τις 3 ετικέτες που είναι εγγυημένα αμετάβλητες για αυτή την παρουσία).

Ισχυρός περιορισμός: χρησιμοποιήστε αυτούς τους helpers σε όλα τα πρότυπά σας. Κανένα όνομα πόρου στα σκληρά, καμία ετικέτα αντιγραμμένη χειροκίνητα.

Συμβουλή: για να περάσετε πολλές τιμές σε έναν helper, χρησιμοποιήστε ένα dict:

yaml
{{ include "hedge.labels" (dict "root" . "composant" "portail") | nindent 4 }}

Ο helper λαμβάνει τότε .root.Release.Name, .root.Values..., και .composant.


Αποστολή 4 — Τρία περιβάλλοντα δίπλα-δίπλα (20 βαθμοί)

Δημιουργήστε τα 3 αρχεία στο chart/environments/ — καθένα επαναορίζει μόνο τις τιμές που διακρίνουν το περιβάλλον του.

Αρχείοenvironmentreplicas (portail + api)nodePort (portail)ΧρώμαΠροτεινόμενο μήνυμα
values-dev.yamldev130130#2563eb« Περιβάλλον ανάπτυξης — προσοχή, όλα μπορούν να αλλάξουν »
values-staging.yamlstaging230131#ea580c« Προ-παραγωγή — μόνο δεδομένα δοκιμής »
values-prod.yamlprod330132#16a34a« Παραγωγή — κάθε ενέργεια έχει πραγματικό αντίκτυπο »

Ανάπτυξη των 3 περιβαλλόντων:

powershell
helm install hedge-dev     .\chart -f .\chart\environments\values-dev.yaml     -n hedge-dev     --create-namespace
helm install hedge-staging .\chart -f .\chart\environments\values-staging.yaml -n hedge-staging --create-namespace
helm install hedge-prod    .\chart -f .\chart\environments\values-prod.yaml    -n hedge-prod    --create-namespace

Περιμένετε να είναι έτοιμα τα Pods (~30 s):

powershell
kubectl wait --for=condition=ready pod --all -n hedge-dev     --timeout=120s
kubectl wait --for=condition=ready pod --all -n hedge-staging --timeout=120s
kubectl wait --for=condition=ready pod --all -n hedge-prod    --timeout=120s

Ανοίξτε τους 3 πίνακες ελέγχου:

powershell
start http://localhost:30130       # DEV — μπλε πανό, 1 αντίγραφο
start http://localhost:30131       # STAGING — πορτοκαλί πανό, 2 αντίγραφα
start http://localhost:30132       # PROD — πράσινο πανό, 3 αντίγραφα

Αναμενόμενο: τρεις σελίδες διαφορετικών χρωμάτων, καθεμία να εμφανίζει το περιβάλλον της, την έκδοσή της, τα Pods της, και το backend της σε πράσινο OK.


Αποστολή 5 — Upgrade έπειτα rollback (10 βαθμοί)

Προσομοιώστε ένα περιστατικό παραγωγής, έπειτα ακυρώστε το.

Σενάριο:

  1. Στο DEV, περάστε το portail.replicas σε 5:
    powershell
    helm upgrade hedge-dev .\chart -f .\chart\environments\values-dev.yaml --set portail.replicas=5 -n hedge-dev
  2. Επαληθεύστε ότι τρέχουν 5 Pods portail:
    powershell
    kubectl get pods -n hedge-dev -l app.kubernetes.io/component=portail
  3. Συμβουλευτείτε το ιστορικό:
    powershell
    helm history hedge-dev -n hedge-dev
    Βλέπετε τουλάχιστον 2 αναθεωρήσεις.
  4. Ακυρώστε την αναβάθμιση επιστρέφοντας στην αναθεώρηση 1:
    powershell
    helm rollback hedge-dev 1 -n hedge-dev
  5. Επαληθεύστε ότι επιστρέψατε σε 1 μόνο Pod portail, και ότι το ιστορικό δείχνει μια νέα αναθεώρηση τύπου Rollback:
    powershell
    kubectl get pods -n hedge-dev -l app.kubernetes.io/component=portail
    helm history hedge-dev -n hedge-dev

Ερώτηση προς επεξεργασία στην έκθεση: ποια είναι η θεμελιώδης διαφορά μεταξύ helm upgrade --set portail.replicas=5 και kubectl scale deploy/hedge-dev-portail --replicas=5; Γιατί το Helm προτιμά να περνάτε από αυτό;


Αποστολή 6 — Έρευνα: επισκευή 3 ελαττωματικών προτύπων (20 βαθμοί)

Ο φάκελος chart/casses/ περιέχει τρία ήδη γραμμένα πρότυπα που μεταγλωττίζονται αλλά εισάγουν καθένα ένα πραγματικό σφάλμα που συναντάται στην επιχείρηση. Πρέπει, για καθένα:

  1. να το αντιγράψετε στο chart/templates/·
  2. να αναπαραγάγετε το σύμπτωμα που περιγράφεται στην κορυφή του αρχείου·
  3. να διαγνώσετε την αιτία διαβάζοντας το μήνυμα σφάλματος·
  4. να το επισκευάσετε (τροποποιώντας το πρότυπο στο chart/templates/, όχι το πρωτότυπο στο casses/
  5. να αποδείξετε ότι η βλάβη εξαφανίστηκε.
ΑρχείοΠροστιθέμενο στοιχείοΦύση του σφάλματος
casse-1-configmap.yamlΈνα καθολικό ConfigMapΣύγκρουση ονόματος μεταξύ releases
casse-2-worker-deployment.yamlΈνα Deployment workerΑμετάβλητος selector παραβιασμένος στο πρώτο helm upgrade
casse-3-cache-deployment.yamlΈνα Deployment cacheΕσφαλμένη διαδρομή τιμής (σιωπηλό τυπογραφικό)

Συμβουλή έρευνας:

powershell
# ΣΤΕΓΝΗ απόδοση ενός μόνο προτύπου (δεν εγκαθιστά τίποτα)
helm template hedge-dev .\chart -f .\chart\environments\values-dev.yaml `
  --show-only templates/casse-3-cache-deployment.yaml --debug

Αυτή η εντολή εκτυπώνει ακριβώς αυτό που το Helm θα έστελνε στο Kubernetes. Είναι το πρώτο σας εργαλείο διάγνωσης — χρησιμοποιήστε την χωρίς μέτρο.


Αποστολή 7 — Μπόνους: η εκλέπτυνση (5 βαθμοί)

Κατ' επιλογή, ένα μόνο αρκεί:

  • a) Προσθέστε ένα hook pre-install (Job) που εμφανίζει Bienvenue dans <environnement> στα ημερολόγια Helm. Η release πρέπει να περιμένει το τέλος του Job πριν συνεχίσει.
  • b) Κάντε τον αριθμό αντιγράφων δυναμικό με μια τιμή values.yaml που έχει εμφωλευμένη δομή (π.χ. portail.autoscaling.enabled, portail.autoscaling.min, portail.autoscaling.max) και δημιουργήστε υπό συνθήκη ένα HorizontalPodAutoscaler ανάλογα με το .enabled.
  • c) Προσθέστε ένα NOTES.txt στο templates/ που εμφανίζει, μετά από κάθε helm install, το ακριβές URL για άνοιγμα του πίνακα ελέγχου (με το σωστό nodePort σύμφωνα με τα Values).

Αυτόματη επικύρωση

Ένα σενάριο σας δίνει τη βαθμολογία σας ανά πάσα στιγμή:

powershell
.\outils\valider.ps1

Παράδειγμα εξόδου σε μερικώς ολοκληρωμένη εργασία:

[OK]    Mission 1 - Chart valide.............. 10/10
[OK]    Mission 2 - Templating de base........ 20/20
[ECHEC] Mission 3 - Helpers et labels.........  0/15   -> helper hedge.selectorLabels manquant
[OK]    Mission 4 - Trois environnements...... 20/20
[ECHEC] Mission 5 - Upgrade + rollback........  0/10   -> aucun rollback detecte dans l'historique
[OK]    Mission 6 - Reparations (3 pannes).... 14/20   -> casse-3 : typo .Values.portal toujours present

SCORE AUTOMATIQUE : 64 / 95

Αν το PowerShell αρνηθεί να εκτελέσει το σενάριο (l'exécution de scripts est désactivée), χρησιμοποιήστε:

powershell
powershell -ExecutionPolicy Bypass -File .\outils\valider.ps1

Παραδοτέα

  1. Ο πλήρης φάκελος chart/, σε λειτουργική κατάσταση (helm lint καθαρό).
  2. Ένα RAPPORT.md που περιέχει:
    • την έξοδο του helm list -A που δείχνει τις 3 releases σας·
    • ένα στιγμιότυπο ανά περιβάλλον (3 χρωματιστοί πίνακες ελέγχου)·
    • το πλήρες ιστορικό του hedge-dev (με upgrade + rollback)·
    • για κάθε βλάβη της αποστολής 6: εντολή διάγνωσης, αιτία, διόρθωση, απόδειξη·
    • τις απαντήσεις σας στις ερωτήσεις προβληματισμού.
  3. Την τελική έξοδο του .\outils\valider.ps1.

Ερωτήσεις προβληματισμού

  1. Γιατί το πεδίο spec.selector.matchLabels είναι αμετάβλητο στο Kubernetes; Ποιο πρόβλημα λύνει αυτός ο περιορισμός;
  2. Έχετε 3 περιβάλλοντα σήμερα. Αύριο, η ομάδα DevSecOps ζητά ένα 4ο (« pre-prod »). Ποια αρχεία δημιουργείτε και ποια δεν αγγίζετε;
  3. Ποια είναι η διαφορά μεταξύ helm upgrade --set replicas=5 και kubectl scale, από την άποψη της ιχνηλασιμότητας και του rollback;
  4. Το portail εμφανίζει « backend OK » — γιατί αυτή η πληροφορία είναι πιο αξιόπιστη από ένα απλό kubectl get svc api;
  5. Τι συμβαίνει αν διαγράψετε ένα Pod με kubectl delete pod, ενώ δημιουργήθηκε από ένα Deployment μέσω Helm; Το Helm γνωρίζει την «απώλεια»;
  6. Ένας συνάδελφος σας προτείνει να βάλετε app.kubernetes.io/version: {{ .Chart.AppVersion }} στο matchLabels ενός Deployment. Τι του απαντάτε;

Βαθμολόγιο

ΣτοιχείοΒαθμοί
Αποστολή 1 — Έγκυρο Chart και καθαρό lint10
Αποστολή 2 — Προτυποποίηση portail + api20
Αποστολή 3 — Επαναχρησιμοποιήσιμοι helpers και ετικέτες15
Αποστολή 4 — Τρία περιβάλλοντα δίπλα-δίπλα20
Αποστολή 5 — Ιχνηλατημένα upgrade + rollback10
Αποστολή 6 — Διάγνωση + επισκευή των 3 βλαβών20
Ποιότητα της έκθεσης και αιτιολόγηση των επιλογών5
Μπόνους — Αποστολή 7+5
Σύνολο100 (+5)

Ποινές:

  • −10 ανά τιμή περιβάλλοντος κωδικοποιημένη στα σκληρά σε πρότυπο (replicas: 3 κατά λέξη αντί για .Values....).
  • −5 ανά άσκοπη επαναορισμό σε values-<env>.yaml (μια τιμή που δεν έχει λόγο να διαφέρει μεταξύ περιβαλλόντων).
  • −10 ανά τροποποίηση αρχείου του apps/.

Εργαλειοθήκη Helm

powershell
# ΑΝΑΛΥΣΗ (καμία ανάπτυξη)
helm lint .\chart                                                        # σύνταξη + καλές πρακτικές
helm template <release> .\chart -f <values.yaml>                         # πλήρης απόδοση
helm template <release> .\chart -f <values.yaml> --show-only templates/<fichier>   # στοχευμένη απόδοση
helm template <release> .\chart -f <values.yaml> --debug                 # με ίχνη
helm show values .\chart                                                 # προεπιλεγμένες τιμές

# ΑΝΑΠΤΥΞΗ
helm install <release> .\chart -f <values.yaml> -n <ns> --create-namespace
helm upgrade <release> .\chart -f <values.yaml> -n <ns>
helm upgrade <release> .\chart -f <values.yaml> --set portail.replicas=5 -n <ns>
helm rollback <release> <revision> -n <ns>
helm uninstall <release> -n <ns>

# ΠΑΡΑΤΗΡΗΣΗ
helm list -A                                                             # όλες οι releases
helm status <release> -n <ns>
helm history <release> -n <ns>
helm get values <release> -n <ns>                                        # οι ενεργές τιμές
helm get manifest <release> -n <ns>                                      # τα εφαρμοσμένα μανιφέστα

Τα 3 αντανακλαστικά σε περίπτωση σφάλματος:

  1. Πάντα να ξεκινάτε από το helm template — είναι ΣΤΕΓΝΗ απόδοση, χωρίς κίνδυνο, που δείχνει ακριβώς τι θα σταλεί στο Kubernetes.
  2. Διαβάστε τη διαδρομή στο μήνυμα σφάλματος — το Helm δίνει πάντα το αρχείο + τη γραμμή + την εσφαλμένη διαδρομή .Values.*.
  3. Το helm get manifest σας δείχνει τι είναι αυτή τη στιγμή στο σύμπλεγμα (χρήσιμο για σύγκριση με αυτό που παράγει το νέο σας πρότυπο).


ΠΑΡΑΡΤΗΜΑ A — Οι εφαρμογές

Μην τροποποιήσετε κανένα από αυτά τα αρχεία. Αντιγράψτε τα ως έχουν στις υποδεικνυόμενες διαδρομές.

A.1 — Το portail (πίνακας ελέγχου πολλαπλών περιβαλλόντων)

Όλες οι εμφανιζόμενες τιμές προέρχονται από μεταβλητές περιβάλλοντος που εγχέει το Helm. Η ίδια εικόνα συμπεριφέρεται διαφορετικά ανάλογα με τα env: του Deployment.

Αρχείο: apps/portail/app.py

python
"""Portail — tableau de bord multi-environnement.

Ce Pod affiche l'environnement dans lequel il tourne (DEV / STAGING / PROD),
la version applicative, le nombre de replicas, et l'etat du backend.

Toutes les valeurs affichees viennent de VARIABLES D'ENVIRONNEMENT injectees
par Helm depuis values-<env>.yaml. Le meme code s'adapte a chaque
environnement sans aucune modification.
"""

import os
import socket
import time
import urllib.error
import urllib.request

from flask import Flask, jsonify, request

app = Flask(__name__)
DEMARRAGE = time.time()


def cfg():
    return {
        "env": os.environ.get("ENVIRONMENT", "inconnu"),
        "version": os.environ.get("APP_VERSION", "0.0.0"),
        "theme": os.environ.get("THEME_COLOR", "#64748b"),
        "message": os.environ.get("BANNIERE_MESSAGE", "Deploye avec Helm"),
        "backend_url": os.environ.get("BACKEND_URL", "http://api"),
        "replicas_info": os.environ.get("REPLICAS_INFO", "?"),
        "pod": socket.gethostname(),
        "uptime": int(time.time() - DEMARRAGE),
    }


def tester_backend(url):
    try:
        with urllib.request.urlopen(url + "/ping", timeout=1.5) as reponse:
            corps = reponse.read(200).decode("utf-8", "ignore")
        return "ok", corps.strip()
    except urllib.error.HTTPError as err:
        return "http", "HTTP %s" % err.code
    except Exception as err:
        return "ko", type(err).__name__


@app.route("/health")
def health():
    return "OK", 200


@app.route("/api-json")
def api_json():
    """Route utile pour la validation automatique."""
    c = cfg()
    etat, detail = tester_backend(c["backend_url"])
    return jsonify(pod=c["pod"], env=c["env"], version=c["version"],
                   backend=etat, backend_detail=detail, uptime=c["uptime"])


@app.route("/")
def accueil():
    c = cfg()
    etat, detail = tester_backend(c["backend_url"])
    # ... (πλήρες πρότυπο HTML στο αρχείο — δεν επαναλαμβάνεται εδώ για αναγνωσιμότητα)

Το πλήρες αρχείο παρέχεται στο apps/portail/app.py.

Αρχείο: apps/portail/requirements.txt

text
flask==3.0.3

Αρχείο: apps/portail/Dockerfile

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]

A.2 — Η api (απλό backend)

Αρχείο: apps/api/app.py

python
"""API — backend simple pour l'exemple Helm."""

import os
import socket
import time

from flask import Flask, jsonify

app = Flask(__name__)
DEMARRAGE = time.time()

ENV = os.environ.get("ENVIRONMENT", "inconnu")
VERSION = os.environ.get("APP_VERSION", "0.0.0")


@app.route("/")
@app.route("/ping")
def ping():
    return jsonify(service="api", env=ENV, version=VERSION,
                   pod=socket.gethostname(),
                   uptime=int(time.time() - DEMARRAGE))


@app.route("/health")
def health():
    return "OK", 200


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Αρχείο: apps/api/requirements.txt

text
flask==3.0.3

Αρχείο: apps/api/Dockerfile

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]


ΠΑΡΑΡΤΗΜΑ B — Σκελετός του Chart

Αντιγράψτε αυτά τα αρχεία, έπειτα αντικαταστήστε κάθε TODO με τη σωστή τιμή. Οι γραμμές που προηγούνται από # ? είναι ερωτήσεις προς απόφαση: σε εσάς εναπόκειται να αποφασίσετε πώς θα συμπληρώσετε τον κώδικα.

Αρχείο: chart/Chart.yaml

yaml
# ? Συμπληρώστε τα υποχρεωτικά πεδία ενός Chart Helm.
# ? Το apiVersion πρέπει να είναι v2 (το v1 είναι παρωχημένο από το Helm 3).
# ? Το type είναι "application" (σε αντίθεση με "library").

apiVersion: TODO
name: hedge
description: TODO
type: TODO
version: 0.1.0
appVersion: "1.0.0"

Αρχείο: chart/values.yaml

yaml
# values.yaml — προεπιλεγμένες τιμές του chart hedge.
# Κάθε περιβάλλον παρέχει ένα αρχείο values-<env>.yaml που ΥΠΕΡΙΣΧΥΕΙ
# αυτών των τιμών από πάνω. Κρατήστε αυτό το αρχείο ΟΥΔΕΤΕΡΟ (καμία τιμή
# ειδική για ένα περιβάλλον).

environment: default

banniere:
  message: "Chart Helm — application multi-environnement"
  couleur: "#64748b"

portail:
  image:
    repository: hedge-portail
    tag: "1.0"
    pullPolicy: IfNotPresent
  replicas: 1
  service:
    type: NodePort
    port: 80
    targetPort: 5000
    nodePort: 30130

api:
  image:
    repository: hedge-api
    tag: "1.0"
    pullPolicy: IfNotPresent
  replicas: 1
  service:
    type: ClusterIP
    port: 80
    targetPort: 8000

Αρχείο: chart/templates/_helpers.tpl

yaml
{{/*
Πλήρες όνομα ενός πόρου : "<release>-<composant>".
Χρήση : {{ include "hedge.fullname" (dict "root" . "composant" "portail") }}
*/}}
{{- define "hedge.fullname" -}}
{{- printf "TODO" .root.Release.Name .composant | trunc 63 | trimSuffix "-" -}}
{{- end -}}


{{/*
Κοινές ετικέτες όλων των πόρων.
Χρήση : {{ include "hedge.labels" (dict "root" . "composant" "portail") | nindent 4 }}
*/}}
{{- define "hedge.labels" -}}
# ? συμπληρώστε τις 7 ετικέτες που ζητούνται στην Αποστολή 3
app.kubernetes.io/name: TODO
app.kubernetes.io/instance: TODO
# ... συνεχίστε ...
{{- end -}}


{{/*
Selector labels : ΣΤΑΘΕΡΟ υποσύνολο των ετικετών.
Βάλτε εδώ ΜΟΝΟ ετικέτες που δεν θα αλλάξουν ΠΟΤΕ για μια παρουσία.
*/}}
{{- define "hedge.selectorLabels" -}}
# ? μόνο οι 3 ΑΥΣΤΗΡΑ αμετάβλητες ετικέτες
{{- end -}}

Αρχείο: chart/templates/portail-deployment.yaml

yaml
# ? Deployment του portail. Χρησιμοποιήστε :
#   - .Values.portail.replicas
#   - .Values.portail.image.{repository,tag,pullPolicy}
#   - .Values.portail.service.targetPort
#   - .Values.environment
#   - .Values.banniere.{couleur,message}
#   - .Chart.AppVersion (για APP_VERSION)
#   - Το ΟΝΟΜΑ του Service api κατασκευασμένο με .Release.Name (για BACKEND_URL)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: TODO
  labels:
    TODO
spec:
  replicas: TODO
  selector:
    matchLabels:
      TODO
  template:
    metadata:
      labels:
        TODO
    spec:
      containers:
        - name: portail
          image: TODO
          imagePullPolicy: TODO
          ports:
            - containerPort: TODO
          env:
            - name: ENVIRONMENT
              value: TODO
            # ? προσθέστε APP_VERSION, THEME_COLOR, BANNIERE_MESSAGE,
            #   BACKEND_URL, REPLICAS_INFO
          readinessProbe:
            httpGet:
              path: /health
              port: TODO
            initialDelaySeconds: 3
            periodSeconds: 5

Αρχείο: chart/templates/portail-service.yaml

yaml
# ? Service για το portail. Τύπος NodePort. Χρησιμοποιήστε τη συνθήκη
#   {{- if eq .Values.portail.service.type "NodePort" }} ... {{- end }}
#   για να συμπεριλάβετε το "nodePort" ΜΟΝΟ αν είναι όντως NodePort.
apiVersion: v1
kind: Service
metadata:
  name: TODO
  labels:
    TODO
spec:
  type: TODO
  selector:
    TODO
  ports:
    - port: TODO
      targetPort: TODO
      # ? nodePort μόνο αν type == NodePort

Αρχείο: chart/templates/api-deployment.yaml

yaml
# ? Ίδια δομή με το portail-deployment.yaml, αλλά :
#   - composant = "api"
#   - μεταβλητές περιβάλλοντος : ENVIRONMENT και APP_VERSION μόνο
#   - θύρα κοντέινερ = .Values.api.service.targetPort (8000)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: TODO
spec:
  # ... (παρόμοια δομή με το portail) ...

Αρχείο: chart/templates/api-service.yaml

yaml
# ? Service ClusterIP για την api. Μία μόνο θύρα. Χωρίς nodePort.
apiVersion: v1
kind: Service
metadata:
  name: TODO
spec:
  type: TODO
  selector:
    TODO
  ports:
    - port: TODO
      targetPort: TODO

Αρχείο: chart/environments/values-dev.yaml

yaml
# ? Περιβάλλον DEV : 1 αντίγραφο, μπλε πανό #2563eb, NodePort 30130.
environment: TODO

banniere:
  message: TODO
  couleur: TODO

portail:
  replicas: TODO
  service:
    nodePort: TODO

api:
  replicas: TODO

Αρχείο: chart/environments/values-staging.yaml

yaml
# ? Περιβάλλον STAGING : 2 αντίγραφα, πορτοκαλί πανό #ea580c, NodePort 30131.
environment: TODO
# ... συμπληρώστε στο μοντέλο του values-dev.yaml ...

Αρχείο: chart/environments/values-prod.yaml

yaml
# ? Περιβάλλον PROD : 3 αντίγραφα, πράσινο πανό #16a34a, NodePort 30132.
environment: TODO
# ...


ΠΑΡΑΡΤΗΜΑ C — Οι τρεις βλάβες προς επισκευή

Κάθε αρχείο παρακάτω βρίσκεται στο chart/casses/. Μην τροποποιήσετε τα πρωτότυπα — αντιγράψτε τα στο chart/templates/, αναπαραγάγετε το σφάλμα, έπειτα διορθώστε το αντίγραφο.

Αρχείο: chart/casses/casse-1-configmap.yaml

yaml
# ΒΛΑΒΗ 1
# Σύμπτωμα : αναπτύξτε hedge-dev, έπειτα δοκιμάστε να αναπτύξετε hedge-staging
# ΣΤΟΝ ΙΔΙΟ ΧΩΡΟ ΟΝΟΜΑΤΩΝ. Η δεύτερη εγκατάσταση αποτυγχάνει με :
#   ConfigMap "hedge-config" ... exists and cannot be imported ...
apiVersion: v1
kind: ConfigMap
metadata:
  name: hedge-config
  labels:
    {{- include "hedge.labels" (dict "root" . "composant" "config") | nindent 4 }}
data:
  timezone: "America/Toronto"
  langue: "fr-CA"

Αρχείο: chart/casses/casse-2-worker-deployment.yaml

yaml
# ΒΛΑΒΗ 2
# Σύμπτωμα : το "helm install" λειτουργεί. Το "helm upgrade" με
# --set environment=recette αποτυγχάνει με :
#   spec.selector: Invalid value: ...: field is immutable
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "hedge.fullname" (dict "root" . "composant" "worker") }}
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name }}
      app.kubernetes.io/instance: {{ .Release.Name }}
      app.kubernetes.io/component: worker
      hedge/environment: {{ .Values.environment | quote }}
  template:
    metadata:
      labels:
        {{- include "hedge.labels" (dict "root" . "composant" "worker") | nindent 8 }}
    spec:
      containers:
        - name: worker
          image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"

Αρχείο: chart/casses/casse-3-cache-deployment.yaml

yaml
# ΒΛΑΒΗ 3
# Σύμπτωμα : το "helm install" αποτυγχάνει με :
#   Error: template ...at <.Values.portal.replicas>:
#   nil pointer evaluating interface {}.replicas
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "hedge.fullname" (dict "root" . "composant" "cache") }}
spec:
  replicas: {{ .Values.portal.replicas }}
  selector:
    matchLabels:
      {{- include "hedge.selectorLabels" (dict "root" . "composant" "cache") | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "hedge.selectorLabels" (dict "root" . "composant" "cache") | nindent 8 }}
    spec:
      containers:
        - name: cache
          image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"


ΠΑΡΑΡΤΗΜΑ D — Το σενάριο επικύρωσης

Το αρχείο outils/valider.ps1 παρέχεται ως έχει. Δεν δίνει καμία λύση — μόνο μια βαθμολογία και το πρώτο σημείο προς διόρθωση. Εκτελέστε το ανά πάσα στιγμή:

powershell
.\outils\valider.ps1

Τι επαληθεύει το σενάριο:

ΑποστολήΑυτόματα κριτήρια
1Το helm lint περνά, το Chart.yaml έχει apiVersion: v2, type: application
2Το helm template παράγει όντως 2 Deployments και 2 Services, ονόματα με πρόθεμα τη release
3Το _helpers.tpl ορίζει τους 3 helpers, παρούσες οι τυπικές ετικέτες
4Τα 3 αρχεία values-<env>.yaml υπάρχουν με τις σωστές τιμές (env, replicas, port, χρώμα), οι 3 releases είναι αναπτυγμένες
5Η release hedge-dev έχει ≥ 2 αναθεωρήσεις και ένα rollback στο ιστορικό
6Κανένα hedge-config στα σκληρά, καμία μεταβλητή ετικέτα στο matchLabels, κανένα .Values.portal (με τυπογραφικό)

Το σενάριο δεν εκτελεί από μόνο του καμία εντολή helm install: είναι δική σας ευθύνη να αναπτύξετε πριν την επικύρωση.


Μάθημα δημιουργημένο από τον Dr. Haythem REHOUMA — Ανάπτυξη και ανάπτυξη λύσεων δεδομένων