Kit του μαθήματος: https://github.com/hrhouma2/aiopsatlas-kubernetes-docker-desktop-labo-fr
Κλωνοποιείς το kit σε έναν φάκελο lab2, επαληθεύεις ότι το Docker Desktop και το Kubernetes είναι έτοιμα, διαβάζεις την κατάσταση ενός άδειου cluster, έπειτα αναπτύσσεις το API whoami της βιβλιοθήκης σε πέντε replicas πίσω από ένα Service LoadBalancer στο http://localhost:8080. Στη συνέχεια σπας δύο πράγματα επίτηδες (μια εικόνα που δεν υπάρχει, ένα ξεχασμένο -n), επιδιορθώνεις, και εκθέτεις το frontend σε NodePort. Κράτα ένα δεύτερο τερματικό ανοιχτό με kubectl get pods -n premiers-pas -w για να βλέπεις τα Pods να κινούνται. Η λεπτομέρεια κάθε βήματος ακολουθεί· ξεκίνα εκτελώντας αυτό το μπλοκ.
Windows (PowerShell)
git clone https://github.com/hrhouma2/aiopsatlas-kubernetes-docker-desktop-labo-fr.git lab2
cd lab2
ls # explorer le contenu : labo.ps1, labo.sh, un dossier par module (01-… à 08-…)
$env:Path = "C:\Program Files\Docker\Docker\resources\bin;" + $env:Path # kubectl de Docker Desktop en priorité
.\labo.ps1 prerequis
.\labo.ps1 etat # cluster vide : attendu docker-desktop Ready, aucun namespace du coursΣε ένα δεύτερο τερματικό (να το κρατήσεις ορατό σε όλο το lab):
kubectl get pods -n premiers-pas -wΤα αρχεία αυτού του lab βρίσκονται στο 01-installer-kubernetes-avec-docker-desktop\pratique\. Έπειτα επαλήθευσε στον browser: http://localhost:8080 (API whoami).
.\labo.ps1 etat # livrable : premiers-pas 7/7 pods Running et deux Services
.\labo.ps1 nettoyer # à la fin, supprime les namespaces du coursΑν το PowerShell αρνείται το .\labo.ps1 («η εκτέλεση scripts είναι απενεργοποιημένη»): Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, απάντησε O, ξαναεκκίνησε.
Linux, macOS, WSL 2, Git Bash
git clone https://github.com/hrhouma2/aiopsatlas-kubernetes-docker-desktop-labo-fr.git lab2
cd lab2
ls # explorer le contenu : labo.sh, labo.ps1, un dossier par module (01-… à 08-…)
./labo.sh prerequis
./labo.sh etat # cluster vide : attendu docker-desktop Ready, aucun namespace du coursΣε ένα δεύτερο τερματικό (να το κρατήσεις ορατό σε όλο το lab):
kubectl get pods -n premiers-pas -wΤα αρχεία αυτού του lab βρίσκονται στο 01-installer-kubernetes-avec-docker-desktop/pratique/. Έπειτα επαλήθευσε στον browser: http://localhost:8080 (API whoami).
./labo.sh etat # livrable : premiers-pas 7/7 pods Running et deux Services
./labo.sh nettoyer # à la fin, supprime les namespaces du coursΕντάσσεσαι στην ομάδα που χτίζει τον κατάλογο της βιβλιοθήκης της πλατφόρμας μαθημάτων. Η προϊσταμένη σου σού δίνει ένα laptop: «Αύριο το πρωί, θέλω το Kubernetes να τρέχει στον σταθμό σου, να μου αποδείξεις με μία εντολή ότι όλα είναι εντάξει, και να μη με καλέσεις την πρώτη φορά που ένα Pod αρνείται να ξεκινήσει.» Θα εγκαταστήσεις λοιπόν το kit του μαθήματος, θα ξετυλίξεις τη λίστα ελέγχου του, θα αναπτύξεις το API και θα το δεις να πολλαπλασιάζεται ζωντανά, έπειτα θα σπάσεις δύο πράγματα επίτηδες: να ζητήσεις μια εικόνα που δεν υπάρχει, και να ξεχάσεις το -n. Και στις δύο περιπτώσεις θα διαβάσεις το μήνυμα, θα ονομάσεις την αιτία και θα επιδιορθώσεις. Το να ξέρεις να διακρίνεις το «το cluster αρνείται αυτό που του ζητώ» από το «κοιτάζω στο λάθος μέρος» είναι αυτό που αποτρέπει μία χαμένη ώρα. Η διαδρομή: kit και prerequis → etat σε κενό → api πίσω από LoadBalancer, υπό -w → πέντε replicas και δέκα αιτήματα → δύο προκλητές βλάβες → επιδιόρθωση → frontend σε NodePort → παραδοτέο.
premiers-pas δεν πρέπει να υπάρχει πια: το kubectl get namespace premiers-pas απαντά NotFound (αλλιώς kubectl delete namespace premiers-pas πρώτα).git clone https://github.com/hrhouma2/aiopsatlas-kubernetes-docker-desktop-labo-fr.git, έπειτα τοποθετήσου στη ρίζα του (αυτή που περιέχει labo.ps1 και labo.sh). Όλες οι παρακάτω εντολές εκτελούνται από εκεί.kubectl get pods -n premiers-pas -w). PowerShell ή bash (Git Bash, WSL 2, macOS, Linux): οι εντολές kubectl είναι ταυτόσημες, και κάθε εντολή του kit υπάρχει και στις δύο γεύσεις (.\labo.ps1 … / ./labo.sh …).$env:Path = "C:\Program Files\Docker\Docker\resources\bin;" + $env:Path.prerequisΤο script του kit κάνει με μία εντολή τις επαληθεύσεις των μαθημάτων 02 και 03: docker, daemon, Kubernetes Docker Desktop, context, εκδόσεις πελάτη/server, helm, μνήμη, θύρες. Παντού σε αυτή την πρακτική, η παραλλαγή bash μιας εντολής του kit προκύπτει αντικαθιστώντας το .\labo.ps1 με ./labo.sh.
.\labo.ps1 prerequisΣημείο ελέγχου: ένα τικ ✔ ανά γραμμή και η τελική φράση Tout est prêt. Πραγματική έξοδος (η έκδοση bash εμφανίζει τις ίδιες γραμμές, με τη διαδρομή /c/Program Files/Docker/Docker/resources/bin/kubectl):
== Prérequis ==
✔ docker : Docker version 29.3.1, build c2be9cc
✔ le démon Docker répond (Docker Engine 29.3.1)
✔ Kubernetes Docker Desktop : running (mode kubeadm, 1 nœud, v1.34.1)
✔ contexte kubectl courant : docker-desktop
✔ kubectl client v1.34.1 (C:\Program Files\Docker\Docker\resources\bin\kubectl.exe)
✔ serveur Kubernetes v1.34.1 (même version mineure que le client)
✔ helm : v4.2.4+g3900f43
✔ mémoire disponible pour Docker : 31 Go
✔ port 8080 : libre
✔ port 8443 : libre
✔ port 30080 : libre
Tout est prêt. Étape suivante : .\labo.ps1 etatΔιάβασε τη γραμμή kubectl client: σου λέει ποιο εκτελέσιμο απαντά, με τη διαδρομή του. Είναι η απάντηση σε μία γραμμή στο πρόβλημα του μαθήματος 03. Το Helm χρησιμεύει μόνο στην ενότητα 7: αν λείπει, η γραμμή γίνεται ! (προειδοποίηση), όχι ✘.
Αν δεις κάτι άλλο: ✘ kubectl client v1.30.0 trop ancien (minimum 1.33) — mettez C:\Program Files\Docker\Docker\resources\bin en tête du PATH ; where.exe kubectl montre l'ordre actuel (πραγματική έξοδος που λήφθηκε με ένα παλιό kubectl στην κορυφή του PATH) → μάθημα 03, βήμα 3· ✘ le démon Docker ne répond pas → το Docker Desktop δεν είναι εκκινημένο· το PowerShell αρνείται να εκτελέσει το script → Set-ExecutionPolicy -Scope CurrentUser RemoteSigned μία και καλή.
etat σε ένα άδειο clusterΠριν δημιουργήσεις οτιδήποτε, κοίτα τι εμφανίζει το kit όταν δεν υπάρχει τίποτα. Θα το συγκρίνεις με το βήμα 9.
.\labo.ps1 etatΣημείο ελέγχου: ο κόμβος Ready, το premiers-pas σημειωμένο absent, κανένα εκτεθειμένο Service. Πραγματική έξοδος (οι γραμμές των άλλων namespaces του μαθήματος, που θα εμφανίζονται ενότητα προς ενότητα, έχουν κοπεί):
== Nœuds ==
NAME STATUS ROLES AGE VERSION
docker-desktop Ready control-plane 18d v1.34.1
== Namespaces du cours ==
— premiers-pas absent
== Services exposés (LoadBalancer / NodePort) dans les namespaces du cours ==
— aucun Service exposé pour l'instant (les leçons en créent avec kubectl expose)Τρία σύμβολα που πρέπει να ξέρεις: ✔ όλα τρέχουν, ! κάτι αξίζει μια ματιά (Pods που δεν είναι Running, μια προειδοποίηση), — ουδέτερη πληροφορία (απόν, τίποτα να εμφανιστεί). Το script κοιτάζει μόνο τα namespaces του μαθήματος: ό,τι ζει στο default ή στο kube-system δεν το ενδιαφέρει.
Στο δεύτερο τερματικό, ξεκίνα την παρακολούθηση και μην την εγκαταλείψεις μέχρι τον καθαρισμό:
kubectl get pods -n premiers-pas -wΔεν συμβαίνει τίποτα όσο το namespace δεν υπάρχει, είναι φυσιολογικό. Στο πρώτο τερματικό:
kubectl create namespace premiers-pas
kubectl create deployment api --image=traefik/whoami:v1.10 --port=80 -n premiers-pas
kubectl expose deployment api --type=LoadBalancer --port=8080 --target-port=80 -n premiers-pas
kubectl get svc -n premiers-pasΣημείο ελέγχου: τρεις επιβεβαιώσεις και έπειτα ένα Service με EXTERNAL-IP localhost.
namespace/premiers-pas created
deployment.apps/api created
service/api exposed
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api LoadBalancer 10.96.92.182 localhost 8080:31427/TCP 5sΣτο μεταξύ, το δεύτερο τερματικό εμφάνισε τη γέννηση του πρώτου Pod, γραμμή προς γραμμή:
NAME READY STATUS RESTARTS AGE
api-9bfb55fc6-mh24c 0/1 Pending 0 0s
api-9bfb55fc6-mh24c 0/1 Pending 0 0s
api-9bfb55fc6-mh24c 0/1 ContainerCreating 0 0s
api-9bfb55fc6-mh24c 1/1 Running 0 2sPending (ο scheduler ψάχνει κόμβο), ContainerCreating (το kubelet ζητά το container από το runtime), Running: δύο δευτερόλεπτα, γιατί η εικόνα είναι ήδη στο μηχάνημα από το μάθημα 04. Επαλήθευσε ότι απαντά:
curl -s http://localhost:8080curl.exe -s http://localhost:8080Hostname: api-9bfb55fc6-mh24c
IP: 10.1.2.255
RemoteAddr: 192.168.65.3:49552
Host: localhost:8080Απόσπασμα: το Hostname είναι το όνομα του Pod που απάντησε, το IP η διεύθυνσή του στο cluster· το RemoteAddr: 192.168.65.3 είναι η διεύθυνση του κόμβου, μέσω της οποίας το Docker Desktop εισάγει το αίτημά σου. Το ίδιο Deployment και το ίδιο Service, γραμμένα σε πλήρες YAML, είναι στο kit: 01-installer-kubernetes-avec-docker-desktop/04-api-declaratif.yaml (ενότητα 2 για να τα διαβάσεις γραμμή προς γραμμή).
Αν δεις κάτι άλλο: EXTERNAL-IP <pending> που δεν κουνιέται → ένα άλλο Service LoadBalancer δημοσιεύει ήδη τη θύρα 8080 (kubectl get svc -A), διάγραψέ το ή άλλαξε θύρα· AlreadyExists → το namespace είχε μείνει από το μάθημα 04, kubectl delete namespace premiers-pas και ξεκίνα ξανά.
Κοίτα καλά το δεύτερο τερματικό τη στιγμή που πληκτρολογείς αυτό:
kubectl scale deployment api --replicas=5 -n premiers-pas
kubectl get pods -n premiers-pas -o wideΣημείο ελέγχου: πέντε Pods Running, καθένα με τη δική του IP 10.1.x.x, όλα στον κόμβο docker-desktop.
deployment.apps/api scaled
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
api-9bfb55fc6-7b7br 1/1 Running 0 15s 10.1.3.1 docker-desktop <none> <none>
api-9bfb55fc6-hp76n 1/1 Running 0 15s 10.1.3.3 docker-desktop <none> <none>
api-9bfb55fc6-mh24c 1/1 Running 0 27s 10.1.2.255 docker-desktop <none> <none>
api-9bfb55fc6-r4d5w 1/1 Running 0 15s 10.1.3.0 docker-desktop <none> <none>
api-9bfb55fc6-rd95r 1/1 Running 0 15s 10.1.3.2 docker-desktop <none> <none>Το πρώτο Pod (mh24c, 27 δευτ.) έχει δώδεκα δευτερόλεπτα παραπάνω από τα τέσσερα άλλα: είναι αυτό του βήματος 3.
Το δεύτερο τερματικό έδειξε τα τέσσερα νέα Pods να περνούν μαζί από Pending, ContainerCreating και έπειτα Running σε τρία δευτερόλεπτα (πραγματικό απόσπασμα):
api-9bfb55fc6-r4d5w 0/1 Pending 0 0s
api-9bfb55fc6-r4d5w 0/1 ContainerCreating 0 0s
api-9bfb55fc6-hp76n 1/1 Running 0 2s
api-9bfb55fc6-r4d5w 1/1 Running 0 3sΤο kit περιέχει ένα μικρό script που στέλνει δέκα αιτήματα και μετρά τα διακριτά Pods που απάντησαν:
.\01-installer-kubernetes-avec-docker-desktop\pratique\repartition.ps1./01-installer-kubernetes-avec-docker-desktop/pratique/repartition.shΠραγματική έξοδος (PowerShell· το script εμφανίζει πρώτα τα δέκα Hostname που λήφθηκαν, ένα ανά γραμμή, έπειτα αυτή την καταμέτρηση):
10 requêtes, 5 Pods distincts ont répondu :
api-9bfb55fc6-7b7br x2
api-9bfb55fc6-hp76n x2
api-9bfb55fc6-mh24c x2
api-9bfb55fc6-r4d5w x2
api-9bfb55fc6-rd95r x2Το ίδιο script εκτελεσμένο σε bash αμέσως μετά έδωσε 10 requêtes, 4 Pods distincts με ένα Pod να σερβίρεται τέσσερις φορές: η κατανομή είναι τυχαία, όχι εκ περιτροπής. Σε δέκα αιτήματα, να δεις τέσσερα ή πέντε Pods είναι φυσιολογικό· να δεις μόνο ένα δεν είναι (βλέπε «Αν κολλήσει»). Το script δεν κάνει τίποτα μαγικό: ένας βρόχος curl που κρατά τη γραμμή Hostname:. Άνοιξέ το για να το διαβάσεις.
Το kit περιέχει ένα Pod του οποίου το tag εικόνας είναι λάθος. Διάβασέ το πριν το εφαρμόσεις: 01-installer-kubernetes-avec-docker-desktop/pratique/01-pod-image-inexistante.yaml.
apiVersion: v1
kind: Pod
metadata:
name: api-cassee
namespace: premiers-pas
labels:
app: api-cassee
partie: bibliotheque
spec:
containers:
- name: whoami
image: traefik/whoami:v9.99
ports:
- containerPort: 80kubectl apply -f 01-installer-kubernetes-avec-docker-desktop/pratique/01-pod-image-inexistante.yaml
kubectl get pods -n premiers-pasΣημείο ελέγχου: το Pod υπάρχει αλλά δεν είναι Running, και τα πέντε άλλα δεν επηρεάζονται.
pod/api-cassee created
NAME READY STATUS RESTARTS AGE
api-9bfb55fc6-7b7br 1/1 Running 0 27s
api-9bfb55fc6-mh24c 1/1 Running 0 39s
api-cassee 0/1 ErrImagePull 0 4s(Τρεις ταυτόσημες γραμμές api-9bfb55fc6-… κομμένες.)
Στο δεύτερο τερματικό, η κατάσταση ταλαντεύεται: το kubelet ξαναδοκιμάζει, αποτυγχάνει, περιμένει όλο και περισσότερο (πραγματικό απόσπασμα):
api-cassee 0/1 ErrImagePull 0 2s
api-cassee 0/1 ImagePullBackOff 0 17s
api-cassee 0/1 ErrImagePull 0 29sΤο get σου λέει ότι αποτυγχάνει· μόνο το describe σου λέει γιατί. Πήγαινε ευθεία στην ενότητα Events, στο τέλος:
kubectl describe pod api-cassee -n premiers-pasΠραγματική έξοδος (μόνο το τέλος εμφανίζεται):
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 34s default-scheduler Successfully assigned premiers-pas/api-cassee to docker-desktop
Normal Pulling 18s (x2 over 34s) kubelet Pulling image "traefik/whoami:v9.99"
Warning Failed 18s (x2 over 34s) kubelet Failed to pull image "traefik/whoami:v9.99": Error response from daemon: failed to resolve reference "docker.io/traefik/whoami:v9.99": docker.io/traefik/whoami:v9.99: not found
Warning Failed 18s (x2 over 34s) kubelet Error: ErrImagePull
Normal BackOff 6s (x2 over 33s) kubelet Back-off pulling image "traefik/whoami:v9.99"
Warning Failed 6s (x2 over 33s) kubelet Error: ImagePullBackOffΌλα είναι εκεί: ποιος (kubelet), τι (Failed to pull image), γιατί (docker.io/traefik/whoami:v9.99: not found), και ο ρυθμός (x2 over 34s). Ένα αντανακλαστικό που πρέπει να χάσεις αμέσως: να ψάχνεις την αιτία στα logs. Δεν υπάρχουν, το container δεν ξεκίνησε ποτέ:
kubectl logs api-cassee -n premiers-pasError from server (BadRequest): container "whoami" in pod "api-cassee" is waiting to start: image can't be pulledΤο RESTARTS μένει στο 0 για τον ίδιο λόγο. Γράψε σε μία φράση την αιτία της βλάβης: θα τη χρειαστείς στο βήμα 9.
-nΘέλεις να επαληθεύσεις το σπασμένο Pod, και πληκτρολογείς την εντολή χωρίς το namespace:
kubectl get pod api-cassee
kubectl logs api-casseeΣημείο ελέγχου: δύο λάθη NotFound, ενώ το Pod υπάρχει κανονικά.
Error from server (NotFound): pods "api-cassee" not found
error: error from server (NotFound): pods "api-cassee" not found in namespace "default"Η δεύτερη γραμμή λέει τα πάντα: in namespace "default". Χωρίς -n, το kubectl ψάχνει στο namespace του context, default, όπου δεν υπάρχει api-cassee. Το Pod δεν εξαφανίστηκε, κοιτάζεις στο λάθος συρτάρι. Απόδειξη:
kubectl get pod api-cassee -n premiers-pasNAME READY STATUS RESTARTS AGE
api-cassee 0/1 ErrImagePull 0 36sΚράτα τον κανόνα: ένα NotFound σε ένα αντικείμενο που μόλις δημιούργησες είναι σχεδόν πάντα ένα ξεχασμένο -n. Αυτό το μάθημα δεν αλλάζει ποτέ το προεπιλεγμένο namespace του context, ακριβώς για να πάρεις τη συνήθεια να το λες σε κάθε εντολή.
kubectl set imageΈνα Pod του οποίου η εικόνα δεν κατεβαίνει δεν επιδιορθώνεται περιμένοντας. Δύο θεραπείες: να το διαγράψεις και να ξαναεφαρμόσεις ένα διορθωμένο YAML, ή να αλλάξεις την εικόνα επιτόπου. Κάνε τη δεύτερη, την πιο γρήγορη, κοιτάζοντας το δεύτερο τερματικό:
kubectl set image pod/api-cassee whoami=traefik/whoami:v1.10 -n premiers-pas
kubectl get pod api-cassee -n premiers-pasΤο whoami είναι το όνομα του container στο YAML (containers[0].name), όχι αυτό της εικόνας.
Σημείο ελέγχου:
pod/api-cassee image updated
NAME READY STATUS RESTARTS AGE
api-cassee 1/1 Running 0 44sΤο δεύτερο τερματικό έδειξε τη μετάβαση ImagePullBackOff → Running ανάμεσα στο 36ο και το 37ο δευτερόλεπτο ζωής του Pod: ένα δευτερόλεπτο, γιατί το traefik/whoami:v1.10 είναι ήδη στο μηχάνημα. Σημείωσε ότι το RESTARTS είναι πάντα 0: το Kubernetes δεν επανεκκίνησε ένα container, εκκίνησε ένα για πρώτη φορά με τη σωστή εικόνα.
frontend σε NodePortΤο API τρέχει. Πρόσθεσε τώρα το δεύτερο στοιχείο της βιβλιοθήκης: ένα Deployment frontend από την εικόνα nginx:1.27-alpine (θύρα 80), εκτεθειμένο από ένα Service τύπου NodePort (όχι LoadBalancer). Έπειτα βρες σε ποια θύρα του μηχανήματός σου απαντά και εμφάνισε τον τίτλο της αρχικής του σελίδας με curl.
Ενδείξεις: τρεις εντολές του μαθήματος 04 αρκούν, αντικαθιστώντας τον τύπο του Service· η θύρα που επιλέγει το Kubernetes διαβάζεται στη στήλη PORT(S) του kubectl get svc, μετά την άνω-κάτω τελεία· στο Docker Desktop, ένα NodePort απαντά στο localhost:<θύρα>. Το kit περιέχει το ισοδύναμο YAML αν προτιμάς: 01-installer-kubernetes-avec-docker-desktop/pratique/02-frontend-nginx-nodeport.yaml.
kubectl create deployment frontend --image=nginx:1.27-alpine --port=80 -n premiers-pas
kubectl expose deployment frontend --type=NodePort --port=80 -n premiers-pas
kubectl get svc frontend -n premiers-pasdeployment.apps/frontend created
service/frontend exposed
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend NodePort 10.111.158.77 <none> 80:32740/TCP 10s80:32740: 80 είναι η θύρα του Service μέσα στο cluster, 32740 η θύρα κόμβου που κληρώθηκε ανάμεσα σε 30000 και 32767. Σε σένα θα είναι διαφορετική: διάβασέ την, μην αντιγράψεις αυτή.
curl -s http://localhost:32740 | grep "<title>"
curl -sI http://localhost:32740 | head -3(PowerShell: curl.exe -s … | Select-String "<title>" και curl.exe -sI … | Select-Object -First 3.)
<title>Welcome to nginx!</title>
HTTP/1.1 200 OK
Server: nginx/1.27.5
Date: Fri, 11 Sep 2026 03:47:01 GMTΤο Server: nginx/1.27.5 επιβεβαιώνει το tag 1.27-alpine. Το EXTERNAL-IP <none> είναι φυσιολογικό για ένα NodePort: κανείς δεν του αποδίδει διεύθυνση, ανοίγει μια θύρα στον κόμβο, και το Docker Desktop αναμεταδίδει αυτή τη θύρα στο localhost. Η ενότητα 4 συγκρίνει τους τρεις τύπους Service αναλυτικά. Με το YAML του kit: το kubectl apply -f 01-installer-kubernetes-avec-docker-desktop/pratique/02-frontend-nginx-nodeport.yaml δημιουργεί τα ίδια δύο αντικείμενα (επαληθευμένο: deployment.apps/frontend created, service/frontend created).
etat και τρεις ερωτήσειςΞαναεκτέλεσε το script του kit και σύγκρινε με το βήμα 2.
.\labo.ps1 etatΠραγματική έξοδος (ίδιες περικοπές όπως στο βήμα 2):
== Nœuds ==
NAME STATUS ROLES AGE VERSION
docker-desktop Ready control-plane 18d v1.34.1
== Namespaces du cours ==
✔ premiers-pas 7/7 pods Running
== Services exposés (LoadBalancer / NodePort) dans les namespaces du cours ==
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
premiers-pas api LoadBalancer 10.96.92.182 localhost 8080:31427/TCP 91s
premiers-pas frontend NodePort 10.111.158.77 <none> 80:32740/TCP 17sΕπτά Pods: πέντε api, το api-cassee επιδιορθωμένο, ένα frontend. Αντίγραψε αυτή την έξοδο στο παραδοτέο σου, έπειτα απάντησε σε μία ή δύο φράσεις την καθεμία:
kubectl logs api-cassee -n premiers-pas δεν μπόρεσε να εμφανίσει τίποτα στο βήμα 5, και πού βρήκες την αιτία;not found in namespace "default": είχε εξαφανιστεί το Pod; Τι θα έπρεπε να είχες πληκτρολογήσει;api δείχνει EXTERNAL-IP localhost και το frontend <none>: ποιον τύπο Service έχει το καθένα, και από ποια θύρα του μηχανήματός σου απαντά το καθένα;.\labo.ps1 prerequis (ή ./labo.sh prerequis) τελειώνει με Tout est prêt.kubectl get all -n premiers-pas δείχνει deployment.apps/api 5/5 5 5, deployment.apps/frontend 1/1 1 1, pod/api-cassee 1/1 Running, ένα replicaset.apps/api-9bfb55fc6 5 5 5 και τα δύο Services (πραγματική έξοδος: επτά Pods, δύο Services, δύο Deployments, δύο ReplicaSets).curl -s http://localhost:8080 | grep Hostname (PowerShell: curl.exe -s http://localhost:8080 | Select-String Hostname) επιστρέφει ένα Hostname: api-… που αλλάζει από κλήση σε κλήση.curl -sI http://localhost:<θύρα του frontend> επιστρέφει HTTP/1.1 200 OK και Server: nginx/1.27.5.ErrImagePull, ImagePullBackOff και not found in namespace "default".Το kit ξέρει να διαγράφει όλα τα namespaces του μαθήματος με μία κίνηση, αλλά αρνείται να το κάνει χωρίς επιβεβαίωση. Κοίτα πρώτα τι θα έκανε:
.\labo.ps1 nettoyer== Nettoyage des namespaces du cours ==
Namespaces qui seront supprimés (avec tout ce qu'ils contiennent) : premiers-pas
Jamais touchés : default, kube-system, kube-public, kube-node-lease.
! rien n'a été supprimé. Pour confirmer : .\labo.ps1 nettoyer -ouiΓια αυτή την ενότητα, διάγραψε μόνο το premiers-pas, με το χέρι, και κράτα το δεύτερο τερματικό ανοιχτό για να δεις τα επτά Pods να περνούν σε Terminating:
kubectl delete namespace premiers-pas
kubectl get namespace premiers-pasnamespace "premiers-pas" deleted
Error from server (NotFound): namespaces "premiers-pas" not foundCtrl+C στο δεύτερο τερματικό. Το http://localhost:8080 δεν απαντά πια (το curl αποτυγχάνει με κωδικό 7, σύνδεση απορρίφθηκε, ή 52, κενή απάντηση). Το .\labo.ps1 nettoyer -oui / ./labo.sh nettoyer --oui θα χρησιμεύσει όταν θέλεις να επαναφέρεις όλο το μάθημα στο μηδέν: δεν αγγίζει ποτέ το default ούτε το kube-system.
Το labo.ps1 αρνείται να εκκινήσει: l'exécution de scripts est désactivée sur ce système → Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, κλείσε και ξανάνοιξε το PowerShell. Το script είναι σε UTF-8 με BOM και λειτουργεί σε PowerShell 5.1 όπως και σε PowerShell 7.
./labo.sh: Permission denied ή /usr/bin/env: 'bash\r': No such file or directory → chmod +x labo.sh για το πρώτο· για το δεύτερο, το Git μετέτρεψε τις καταλήξεις γραμμής σε CRLF κατά την εξαγωγή: sed -i 's/\r$//' labo.sh (ή git config core.autocrlf false και ξανακλωνοποίηση).
Το prerequis εμφανίζει ✘ port 8080 déjà occupé par <programme> (PID …) — arrêtez-le ou choisissez un autre port dans les leçons → μια τοπική εφαρμογή ακούει ήδη (ένας άλλος server ανάπτυξης, ένα ξεχασμένο port-forward)· το script ονομάζει τη διεργασία. Κλείσε την, ή διάλεξε --port=8081 στο βήμα 3 και προσάρμοσε τα URL. Αν η θύρα κατέχεται από ένα Service Kubernetes του μαθήματος, η γραμμή μένει ✔: utilisé par un Service du cours (LoadBalancer ou NodePort).
EXTERNAL-IP <pending> στο βήμα 3 → στο Docker Desktop, η ζητούμενη θύρα δημοσιεύεται ήδη από ένα άλλο Service LoadBalancer (επαληθευμένο: ένα δεύτερο Service στην 8080 μένει <pending> όσο υπάρχει το πρώτο). Το kubectl get svc -A δείχνει ποιο. Σε kind ή minikube, το <pending> είναι η φυσιολογική κατάσταση: χρησιμοποίησε kubectl port-forward.
Το repartition επιστρέφει δέκα φορές το ίδιο Hostname → είτε το scale δεν έχει τελειώσει ακόμη (kubectl get pods -n premiers-pas: περίμενε πέντε Running), είτε το Service έχει μόνο ένα endpoint: το kubectl get endpointslice -n premiers-pas πρέπει να λιστάρει πέντε IP (10.1.2.255,10.1.3.3,10.1.3.0 + 2 more... στο μηχάνημα του μαθήματος).
Μετά το set image, το api-cassee μένει σε ImagePullBackOff → πληκτρολόγησες λάθος όνομα container ή tag: το kubectl describe pod api-cassee -n premiers-pas δείχνει την εικόνα που πραγματικά ζητήθηκε στο Containers: whoami: Image:. Το όνομα αριστερά του = είναι αυτό του container (whoami), όχι της εικόνας.
labo.ps1 prerequis / labo.sh prerequis επαληθεύει με μία εντολή αυτά που τα μαθήματα 02 και 03 έκαναν με το χέρι, και ονομάζει το εκτελέσιμο kubectl που απαντά.labo.ps1 etat συνοψίζει κόμβο, Pods ανά namespace του μαθήματος και εκτεθειμένα Services: είναι η φωτογραφία που επισυνάπτεις όταν ζητάς βοήθεια.kubectl get pods -w, ένα Pod περνά από Pending, ContainerCreating, Running· πέντε replicas γεννιούνται σε τρία δευτερόλεπτα όταν η εικόνα είναι ήδη εκεί.ErrImagePull και έπειτα ImagePullBackOff = η εικόνα δεν κατεβαίνει· η αιτία είναι στο kubectl describe, ενότητα Events, ποτέ στο kubectl logs (το container δεν ξεκίνησε).not found in namespace "default" = ξεχασμένο -n· το αντικείμενο είναι πάντα εκεί, σε άλλο namespace.kubectl set image pod/<όνομα> <container>=<εικόνα> διορθώνει μια εικόνα επιτόπου· ένα Service NodePort απαντά στο localhost:<30000-32767> με Docker Desktop, ένα LoadBalancer στη θύρα που επέλεξες.Χωρίς να διαγράψεις το namespace, προκάλεσε μια τρίτη βλάβη και επιδιόρθωσέ την: πέρασε το Deployment api σε ένα ανύπαρκτο tag με kubectl set image deployment/api whoami=traefik/whoami:v9.99 -n premiers-pas, έπειτα παρατήρησε στο δεύτερο τερματικό ότι το Kubernetes δεν καταστρέφει τα Pods που δουλεύουν: στο μηχάνημα του μαθήματος, δημιούργησε τρία Pods api-78d7f59657-… σε ErrImagePull, αφαίρεσε ένα μόνο παλιό, κράτησε τέσσερα api-9bfb55fc6-… σε Running, και σταμάτησε εκεί (το kubectl rollout status deployment/api -n premiers-pas μένει στο Waiting for deployment "api" rollout to finish: 3 out of 5 new replicas have been updated...). Το http://localhost:8080 συνεχίζει να απαντά. Επιδιόρθωσε με kubectl rollout undo deployment/api -n premiers-pas (deployment.apps/api rolled back) και επαλήθευσε ότι τα σπασμένα Pods εξαφανίζονται και ότι πέντε api-9bfb55fc6-… τρέχουν. Μόλις είδες το rolling update, τα προστατευτικά του (maxSurge, maxUnavailable) και το rollback, θέματα της ενότητας 3.