Διαγράμματα: Kubernetes
Το έγγραφο αυτό αποτελεί οπτική αναφορά για το Kubernetes workshop. Συμπληρώνει τα έγγραφα εννοιών, αρχιτεκτονικής, βέλτιστων πρακτικών, αναφοράς εντολών και προγράμματος σπουδών με επεξηγηματικά διαγράμματα, ακολουθίες και ροές αντιμετώπισης προβλημάτων.
Τα διαγράμματα έχουν σχεδιαστεί για διδασκαλία και δεν αποτυπώνουν κάθε λεπτομέρεια υλοποίησης. Εστιάζουν στις σχέσεις, τις ευθύνες και τις διαδρομές αποφάσεων που πρέπει να μπορείς να εξηγήσεις, να συζητήσεις και να αναπαράγεις στις πρακτικές ασκήσεις του workshop.
1. Σημειώσεις χρήσης
1.1 Σκοπός της συλλογής διαγραμμάτων
Χρησιμοποίησε αυτή τη συλλογή για να κατανοήσεις το Kubernetes οπτικά και μέσα από πρακτικά παραδείγματα. Κάθε διάγραμμα απαντά σε ένα συνηθισμένο ερώτημα του workshop:
- Ποιο Component έχει κάθε ευθύνη;
- Ποιο Resource δημιουργεί ή ελέγχει κάποιο άλλο Resource;
- Πού αποθηκεύεται το Desired State;
- Σε ποιο σημείο ξεκινά μια αστοχία;
- Ποιο σημείο ελέγχεις πρώτα;
- Ποιες ευθύνες ανήκουν στο Kubernetes, σε ένα add-on, στον Cloud Provider ή σε εσένα;
Τα διαγράμματα μπορούν να χρησιμοποιηθούν σε παρουσιάσεις, εξηγήσεις στον πίνακα, ομαδικές ασκήσεις και Labs αντιμετώπισης προβλημάτων.
1.2 Τύποι διαγραμμάτων
| Τύπος διαγράμματος | Σκοπός | Τυπική χρήση |
|---|---|---|
flowchart |
Components, ροές δεδομένων και εξαρτήσεις | Αρχιτεκτονική, δίκτυο, Storage και ασφάλεια |
sequenceDiagram |
Ροές με χρονική σειρά | API requests, Rollout, DNS, Admission και kubeadm |
stateDiagram-v2 |
Καταστάσεις και μεταβάσεις | Pod Lifecycle, Rollout και Incident Response |
| Δέντρο αποφάσεων | Διαδρομές ανάλυσης | Troubleshooting και αποφάσεις σχεδιασμού |
1.3 Πεδίο εφαρμογής και όρια των διαγραμμάτων
Το Kubernetes είναι επεκτάσιμο. Η μορφή ενός διαγράμματος μπορεί να διαφέρει ανάλογα με τη διανομή και τις πρόσθετες υπηρεσίες. Ένα Managed Kubernetes Cluster, ένα Cluster με kubeadm, OpenShift, k3s ή Talos, καθώς και λύσεις όπως Cilium, Calico, Istio, Argo CD ή ένας Cloud Load Balancer αλλάζουν τις λεπτομέρειες υλοποίησης. Η βασική λογική παραμένει ίδια: API, Desired State, Controllers, Scheduler, kubelet, Runtime, δίκτυο, Storage, ασφάλεια και Observability συνεργάζονται.
2. Γενική εικόνα και αρχιτεκτονική Cluster
2.1 Από τη δήλωση της επιθυμητής κατάστασης στην εφαρμογή που εκτελείται
Το διάγραμμα δείχνει τη συνολική ροή: δηλώνεις ένα Desired State, το Kubernetes το αποθηκεύει και οι Controllers μαζί με τα Components των Nodes εργάζονται ώστε το Actual State να συμφωνεί με αυτό.
flowchart LR
user["Εσύ / ομάδα"] --> intent["Desired State"]
intent --> manifest["YAML, Helm, Kustomize ή GitOps"]
manifest --> api["Kubernetes API Server"]
api --> etcd["etcd: κατάσταση Cluster"]
api --> controllers["Controllers"]
api --> scheduler["Scheduler"]
scheduler --> node["Worker Node"]
controllers --> node
node --> kubelet["kubelet"]
kubelet --> runtime["Container Runtime"]
runtime --> pods["Pods και Containers"]
pods --> service["Service Discovery και δίκτυο"]
pods --> storage["Volumes και Storage"]
pods --> signals["Logs, Metrics, Events"]
signals --> user
Βασικός κανόνας: Το Kubernetes δεν εκκινεί απλώς Containers. Διαχειρίζεται το Desired State μέσω του API και διορθώνει συνεχώς τις αποκλίσεις.
2.2 Control Plane και Worker Nodes
Το Control Plane λαμβάνει αποφάσεις και συντονίζει το Cluster. Οι Worker Nodes εκτελούν τα Workloads. Το API Server είναι η κεντρική διεπαφή· οι άμεσες αλλαγές στους Nodes παρακάμπτουν το μοντέλο Kubernetes και συνήθως δεν μπορούν να αναπαραχθούν.
flowchart TD
subgraph cp["Control Plane"]
api["kube-apiserver"]
etcd["etcd"]
sched["kube-scheduler"]
cm["kube-controller-manager"]
ccm["cloud-controller-manager"]
end
subgraph n1["Worker Node A"]
kubelet1["kubelet"]
proxy1["kube-proxy ή eBPF dataplane"]
cni1["CNI Plugin"]
rt1["containerd ή CRI-O"]
pods1["Pods"]
end
subgraph n2["Worker Node B"]
kubelet2["kubelet"]
proxy2["kube-proxy ή eBPF dataplane"]
cni2["CNI Plugin"]
rt2["containerd ή CRI-O"]
pods2["Pods"]
end
api --> etcd
api --> sched
api --> cm
api --> ccm
api --> kubelet1
api --> kubelet2
kubelet1 --> rt1 --> pods1
kubelet2 --> rt2 --> pods2
cni1 --> pods1
cni2 --> pods2
proxy1 --> pods1
proxy2 --> pods2
Σημείωση workshop: Ρώτησε ποιο Component εκκινεί πραγματικά ένα Pod. Δεν είναι ο Scheduler· το kubelet το εκκινεί μέσω του Container Runtime. Ο Scheduler επιλέγει μόνο τον κατάλληλο Node.
2.3 Control Plane υψηλής διαθεσιμότητας
Σε περιβάλλοντα Production, εκτέλεσε πλεονάζοντα Components του Control Plane. Το API Server μπορεί να κλιμακωθεί οριζόντια. Το etcd χρειάζεται Quorum και απαιτεί ιδιαίτερη προστασία, Backup και Monitoring.
flowchart TD
client["kubectl, Controllers, CI/CD, GitOps"] --> lb["Load Balancer για API Servers"]
lb --> api1["API Server 1"]
lb --> api2["API Server 2"]
lb --> api3["API Server 3"]
api1 --> e1["etcd Member 1"]
api2 --> e2["etcd Member 2"]
api3 --> e3["etcd Member 3"]
e1 <--> e2
e2 <--> e3
e1 <--> e3
api1 --> sched["Scheduler με Leader Election"]
api2 --> cm["Controller Manager με Leader Election"]
api3 --> ccm["Cloud Controller Manager"]
Βασικός κανόνας: Ο πλεονασμός των API Servers προστατεύει τη διεπαφή ελέγχου. Το Quorum του etcd προστατεύει την κατάσταση του Cluster. Χωρίς δοκιμασμένο Backup του etcd δεν υπάρχει αξιόπιστη διαδικασία Disaster Recovery.
2.4 Stacked etcd και External etcd
Σε αυτοδιαχειριζόμενα Clusters που δημιουργούνται με kubeadm, η τοπολογία του etcd είναι σημαντική αρχιτεκτονική απόφαση. Το Stacked etcd απαιτεί λιγότερους Nodes, ενώ το External etcd διαχωρίζει σαφέστερα τις ευθύνες.
flowchart LR
subgraph stacked["Stacked Control Plane"]
cp1["Control Plane Node 1\nAPI + etcd"]
cp2["Control Plane Node 2\nAPI + etcd"]
cp3["Control Plane Node 3\nAPI + etcd"]
cp1 <--> cp2
cp2 <--> cp3
cp1 <--> cp3
end
subgraph external["Τοπολογία External etcd"]
apiA["Control Plane Nodes\nAPI, Scheduler, Controller"]
etcdA["Αποκλειστικός etcd Node 1"]
etcdB["Αποκλειστικός etcd Node 2"]
etcdC["Αποκλειστικός etcd Node 3"]
apiA --> etcdA
apiA --> etcdB
apiA --> etcdC
etcdA <--> etcdB
etcdB <--> etcdC
etcdA <--> etcdC
end
Βοήθημα απόφασης: Επίλεξε Stacked etcd για μικρότερες και απλούστερες εγκαταστάσεις. Επίλεξε External etcd όταν χρειάζεσαι μεγαλύτερο διαχωρισμό, ειδικές λειτουργικές διαδικασίες και σαφή κατανομή ευθυνών.
2.5 Το εσωτερικό ενός Worker Node
Ένας Node δεν είναι απλώς μια VM ή ένας Server. Το Kubernetes βασίζεται στο kubelet, στο Container Runtime, σε Components δικτύου, σε Pod Sandboxes και σε τοπικά Logs. Συχνά εκτελούνται και πρόσθετα DaemonSets.
flowchart TD
api["API Server"] --> kubelet["kubelet"]
subgraph node["Worker Node"]
kubelet --> cri["CRI interface"]
cri --> runtime["containerd ή CRI-O"]
runtime --> sandbox["Pod Sandbox"]
sandbox --> c1["App Container"]
sandbox --> c2["Sidecar Container"]
kubelet --> volumes["Volume Mounts"]
kubelet --> probes["Liveness, Readiness, Startup Probes"]
kubelet --> logs["Container Logs"]
proxy["kube-proxy ή eBPF"] --> dataplane["Service dataplane"]
cni["CNI Plugin"] --> podnet["Δίκτυο Pods"]
ds["DaemonSet Pods"] --> nodeagents["Monitoring, Logging, ασφάλεια, CNI"]
end
Ερώτηση αξιολόγησης: Αν ένα Pod δεν ξεκινά, ποια στοιχεία ελέγχεις πέρα από το Manifest; Εξέτασε την κατάσταση του Node, το kubelet, το Runtime, το CNI, το Image Pull, τα Volumes, τους διαθέσιμους πόρους και τα Events.
2.6 Επικοινωνία από το Control Plane προς τους Nodes
Το API Server επικοινωνεί με το kubelet και μπορεί να χρησιμοποιήσει τη λειτουργία Proxy για πρόσβαση σε Node, Pod ή Service. Πολλές εντολές Debugging λειτουργούν μόνο όταν αυτές οι διαδρομές είναι προσβάσιμες και η πρόσβαση επιτρέπεται.
flowchart LR
api["API Server"] -->|Ανάγνωση κατάστασης Pod| kubelet["kubelet"]
api -->|Logs, exec, port-forward, debug| kubelet
kubelet -->|Αναφορά κατάστασης Node και Pod| api
api -->|Διαδρομή Proxy| target["Node, Pod ή Service"]
target --> response["Απάντηση στον API Client"]
response --> user["kubectl"]
Σημείωση Troubleshooting: Αν αποτύχουν τα kubectl logs, kubectl exec ή kubectl port-forward, έλεγξε την πρόσβαση στο API, το RBAC, τη θύρα του kubelet, το δίκτυο του Node και την κατάσταση του ίδιου του kubelet.
2.7 Kubernetes Components ανά πεδίο ευθύνης
Κανένα Component δεν επιλύει όλα τα προβλήματα. Το διάγραμμα βοηθά να αντιστοιχίσεις γρήγορα μια αστοχία στο κατάλληλο επίπεδο της πλατφόρμας.
flowchart TD
platform["Πλατφόρμα"] --> api["API και κατάσταση"]
platform --> scheduling["Scheduling"]
platform --> runtime["Runtime"]
platform --> network["Δίκτυο"]
platform --> storage["Storage"]
platform --> security["Ασφάλεια"]
platform --> observe["Observability"]
api --> apiserver["kube-apiserver"]
api --> etcd["etcd"]
scheduling --> scheduler["kube-scheduler"]
scheduling --> autoscaler["Cluster Autoscaler"]
runtime --> kubelet["kubelet"]
runtime --> crio["CRI Runtime"]
network --> cni["CNI"]
network --> service["Service dataplane"]
storage --> csi["CSI"]
storage --> pv["PV, PVC, StorageClass"]
security --> rbac["RBAC"]
security --> admission["Admission"]
security --> pss["Pod Security"]
observe --> metrics["Metrics"]
observe --> logs["Logs"]
observe --> traces["Traces"]
3. API, μοντέλο Resources και Reconciliation
3.1 Κύκλος ζωής ενός API Request
Κάθε αλλαγή περνά από το API Server. Το Authentication, το Authorization, το Admission και η αποθήκευση της κατάστασης είναι ξεχωριστά βήματα. Η διάκρισή τους είναι κρίσιμη για την ασφάλεια και το Troubleshooting.
sequenceDiagram
participant U as Χρήστης ή Tool
participant API as API Server
participant AUTHN as Authentication
participant AUTHZ as Authorization
participant ADM as Admission Control
participant ETCD as etcd
participant CTRL as Controller
U->>API: apply, create, patch ή delete
API->>AUTHN: Ποιος υποβάλλει το Request?
AUTHN-->>API: Ταυτότητα
API->>AUTHZ: Επιτρέπεται η ενέργεια σε αυτή την ταυτότητα?
AUTHZ-->>API: Επιτρέπεται ή απορρίπτεται
API->>ADM: Validation και Mutation
ADM-->>API: Αποδοχή ή απόρριψη
API->>ETCD: Αποθήκευση κατάστασης
ETCD-->>API: Η κατάσταση αποθηκεύτηκε
API-->>U: Απάντηση API
CTRL->>API: Παρακολούθηση αλλαγής
CTRL->>API: Προσαρμογή του Actual State
Βασικός κανόνας: Το kubectl apply ενημερώνει το Desired State μόνο αφού το API Server αποδεχθεί το Request και το αποθηκεύσει. Η υλοποίηση της αλλαγής γίνεται έπειτα ασύγχρονα από τους Controllers και το kubelet.
3.2 Δομή ενός Kubernetes Object
Σχεδόν κάθε Kubernetes Object ακολουθεί το ίδιο μοντέλο: τύπος, Metadata, Desired State και παρατηρούμενη κατάσταση.
flowchart TD
obj["Kubernetes Object"] --> apiVersion["apiVersion"]
obj --> kind["kind"]
obj --> metadata["metadata"]
obj --> spec["spec"]
obj --> status["status"]
metadata --> name["name"]
metadata --> namespace["namespace"]
metadata --> labels["labels"]
metadata --> annotations["annotations"]
metadata --> owner["ownerReferences"]
metadata --> finalizers["finalizers"]
spec --> desired["Desired State"]
status --> actual["Παρατηρούμενη κατάσταση"]
status --> conditions["Conditions"]
status --> observed["observedGeneration"]
Σημείωση workshop: Ζήτησε από τους συμμετέχοντες να εξετάσουν την έξοδο του kubectl get deployment demo -o yaml και να εντοπίσουν τα spec, status, metadata.generation και status.observedGeneration.
3.3 Desired State, Actual State και Reconciliation
Οι Controllers λειτουργούν σε συνεχείς βρόχους: παρακολουθούν Resources, συγκρίνουν το Desired State με το Actual State, εκτελούν διορθωτικές ενέργειες και ενημερώνουν το Status.
flowchart LR
desired["Desired State\nστο API Object"] --> compare["Ο Controller συγκρίνει"]
actual["Actual State\nστο Cluster"] --> compare
compare -->|Απόκλιση| act["Εκτέλεση ενέργειας"]
act --> actual
compare -->|Χωρίς απόκλιση| steady["Σταθερή κατάσταση"]
act --> status["Ενημέρωση Status"]
status --> desired
Βασικός κανόνας: Στο Kubernetes περιγράφεις κυρίως πώς πρέπει να είναι η κατάσταση του συστήματος, αντί να δίνεις μια εντολή που εκτελείται μία φορά.
3.4 Ο βρόχος ενός Controller αναλυτικά
Ένας Controller δεν είναι μια αδιαφανής διεργασία παρασκηνίου. Αντιδρά σε Events, χρησιμοποιεί τοπικές Caches και προσπαθεί να διορθώσει Resources που λείπουν ή έχουν λανθασμένη κατάσταση.
flowchart TD
watch["Παρακολούθηση API Resources"] --> queue["Work Queue"]
queue --> reconcile["Λειτουργία Reconcile"]
reconcile --> read["Ανάγνωση τρέχουσας κατάστασης"]
read --> decide{Είναι σωστό το Actual State?}
decide -->|Ναι| status["Έλεγχος ή ενημέρωση Status"]
decide -->|Όχι| change["Δημιουργία, ενημέρωση ή διαγραφή Resources"]
change --> requeue["Επιστροφή στο Queue αν χρειάζεται"]
status --> wait["Αναμονή επόμενης αλλαγής"]
requeue --> queue
wait --> watch
Λειτουργική σημασία: Αν ένας Controller δεν λειτουργεί, τα API Objects μπορεί να εξακολουθούν να υπάρχουν, ενώ το Actual State δεν αλλάζει όπως αναμένεται.
3.5 Owner References και Garbage Collection
Το Kubernetes χρησιμοποιεί Owner References για να συνδέει εξαρτώμενα Resources με τον ιδιοκτήτη τους. Έτσι μπορεί να αφαιρεί αυτόματα παράγωγα Objects όταν διαγράφεται ο ιδιοκτήτης τους.
flowchart TD
dep["Deployment"] -->|ownerReference| rs1["ReplicaSet παλιάς έκδοσης"]
dep -->|ownerReference| rs2["ReplicaSet νέας έκδοσης"]
rs2 -->|ownerReference| pod1["Pod 1"]
rs2 -->|ownerReference| pod2["Pod 2"]
rs1 --> oldpod["Παλιό Pod"]
delete["Το Deployment διαγράφεται"] --> gc["Garbage Collector"]
gc --> rs1
gc --> rs2
gc --> pod1
gc --> pod2
Ερώτηση αξιολόγησης: Γιατί δεν πρέπει να τροποποιείς χειροκίνητα τα ReplicaSets ή τα Pods ενός Deployment ως κύρια λειτουργική πρακτική; Επειδή ο Controller θα τα επαναφέρει ή θα τα αντικαταστήσει σύμφωνα με το Desired State του Deployment.
3.6 Finalizers και ελεγχόμενη διαγραφή
Οι Finalizers εμποδίζουν την άμεση οριστική διαγραφή ενός Object. Ένας Controller μπορεί έτσι να καθαρίσει εξωτερικούς πόρους πριν αφαιρεθεί το Object.
sequenceDiagram
participant U as Χρήστης
participant API as API Server
participant OBJ as Object με Finalizer
participant C as Controller
participant EXT as Εξωτερικό Resource
U->>API: Διαγραφή Object
API->>OBJ: Ορισμός deletionTimestamp
API-->>U: Το Object βρίσκεται σε διαδικασία διαγραφής
C->>API: Εντοπισμός Object με deletionTimestamp
C->>EXT: Καθαρισμός εξωτερικού Resource
EXT-->>C: Ο καθαρισμός ολοκληρώθηκε
C->>API: Αφαίρεση Finalizer
API->>API: Οριστική διαγραφή Object
Σημείωση Troubleshooting: Αν ένα Namespace, PVC ή Custom Resource παραμένει για πολλή ώρα σε κατάσταση Terminating, έλεγξε τους Finalizers και τον υπεύθυνο Controller.
3.7 Conditions, Status και Events
Τα Conditions, το Status και τα Events είναι κρίσιμα λειτουργικά σήματα. Δείχνουν τι προσπάθησε να κάνει το Kubernetes και γιατί κάτι δεν λειτουργεί.
flowchart LR
obj["Resource"] --> status["status"]
obj --> events["Events"]
status --> conditions["Conditions"]
conditions --> ready["Ready"]
conditions --> available["Available"]
conditions --> progressing["Progressing"]
conditions --> degraded["Degraded ή Failed"]
events --> schedule["Events του Scheduling"]
events --> image["Events του Image Pull"]
events --> volume["Events των Volumes"]
events --> probe["Events των Probes"]
Πρακτική workshop: Το kubectl describe είναι συχνά η ταχύτερη αφετηρία, επειδή παρουσιάζει μαζί Status, Conditions και Events.
4. Workloads και Pod Lifecycle
4.1 Deployment, ReplicaSet και Pods
Ένα Deployment δεν διαχειρίζεται απευθείας Containers. Δημιουργεί ReplicaSets, τα οποία εξασφαλίζουν τον επιθυμητό αριθμό όμοιων Pods.
flowchart TD
deploy["Deployment\napp=web"] --> rs["ReplicaSet\nreplicas=3"]
rs --> pod1["Pod web-1"]
rs --> pod2["Pod web-2"]
rs --> pod3["Pod web-3"]
svc["Service\nselector app=web"] --> pod1
svc --> pod2
svc --> pod3
Βασικός κανόνας: Το Deployment ορίζει τη στρατηγική Rollout και το Pod Template. Το ReplicaSet διατηρεί τον αριθμό αντιγράφων. Το Service εντοπίζει τα κατάλληλα Pods μέσω Labels.
4.2 Rolling Update ενός Deployment
Κατά τη διάρκεια ενός Rolling Update, το Kubernetes δημιουργεί νέο ReplicaSet και μειώνει σταδιακά το παλιό. Τα maxSurge και maxUnavailable ορίζουν πόσο γρήγορα μπορεί να γίνει η μετάβαση.
sequenceDiagram
participant U as Χρήστης
participant API as API Server
participant D as Deployment Controller
participant OLD as Παλιό ReplicaSet
participant NEW as Νέο ReplicaSet
participant SVC as Service
U->>API: Νέο Image μέσω apply ή set image
API-->>D: Το Deployment άλλαξε
D->>NEW: Δημιουργία νέου ReplicaSet
D->>NEW: Αύξηση νέων Pods
NEW-->>SVC: Τα Pods είναι Ready
D->>OLD: Μείωση παλιών Pods
D->>API: Ενημέρωση κατάστασης Rollout
Σημείωση workshop: Κατά τη διάρκεια του Update, σύγκρινε παράλληλα τις εξόδους των kubectl rollout status, kubectl get rs και kubectl get pods -w.
4.3 Rollback ενός Deployment
Το Rollback χρησιμοποιεί το αποθηκευμένο ιστορικό Rollout. Δεν υποκαθιστά τη σωστή διαχείριση εκδόσεων, αλλά είναι σημαντικός λειτουργικός μηχανισμός.
flowchart LR
bad["Ελαττωματικό Release v3"] --> detect["Εντοπισμός σφάλματος"]
detect --> undo["kubectl rollout undo"]
undo --> previous["Αύξηση Replicas του ReplicaSet v2"]
previous --> down["Μείωση Replicas του ReplicaSet v3"]
down --> verify["Έλεγχος Service, Logs και Metrics"]
Ερώτηση αξιολόγησης: Τι συμβαίνει αν ένα ConfigMap ή μια εξωτερική Database Migration δεν είναι συμβατή με την προηγούμενη έκδοση; Τότε το Rollback μόνο του Deployment δεν αρκεί.
4.4 Pod Lifecycle
Ένα Pod περνά από διάφορες καταστάσεις. Πολλές αστοχίες γίνονται πιο κατανοητές όταν εξετάζεις χωριστά τη φάση του Pod, την κατάσταση των Containers και τα Events.
stateDiagram-v2
[*] --> Pending
Pending --> Running: Ανάθεση σε Node και εκκίνηση Containers
Pending --> Failed: Αποτυχία Scheduling, Image ή Volume
Running --> Succeeded: Όλα τα Containers ολοκληρώθηκαν
Running --> Failed: Μόνιμη αποτυχία Container ή Pod
Running --> Terminating: Διαγραφή ή Eviction
Terminating --> [*]
Succeeded --> [*]
Failed --> [*]
Σημαντικό: Το CrashLoopBackOff δεν είναι φάση Pod· είναι λόγος αναμονής ενός Container. Έλεγξε τα kubectl describe pod και kubectl logs --previous.
4.5 Init Container, App Container και Sidecar Pattern
Τα Init Containers εκτελούνται πριν από τα κανονικά App Containers. Τα Sidecars συμπληρώνουν την εφαρμογή κατά την εκτέλεση, για παράδειγμα με Proxy, Logging ή συγχρονισμό.
flowchart TD
start["Το Pod ξεκινά"] --> init1["Init Container 1"]
init1 --> init2["Init Container 2"]
init2 --> app["App Container"]
init2 --> sidecar["Sidecar Container"]
app <--> sharednet["Κοινό Network Namespace"]
sidecar <--> sharednet
app <--> volume["Κοινά Volumes"]
sidecar <--> volume
Ερώτηση σχεδιασμού: Ανήκει πράγματι αυτή η λειτουργία στο ίδιο Pod ή θα ήταν σαφέστερο ένα ξεχωριστό Service; Ένα Sidecar συνδέει στενά το Lifecycle, τους πόρους και την κλιμάκωσή του με την εφαρμογή.
4.6 Probes και συμμετοχή στην κυκλοφορία
Τα Probes επηρεάζουν την αυτόματη αποκατάσταση και τη δρομολόγηση της κυκλοφορίας. Το Readiness Probe καθορίζει αν ένα Pod δέχεται κυκλοφορία από Service. Το Liveness Probe καθορίζει αν το kubelet επανεκκινεί ένα Container. Το Startup Probe προστατεύει εφαρμογές με αργή εκκίνηση.
flowchart TD
pod["Pod"] --> startup["Startup Probe"]
startup -->|Επιτυχία| live["Ενεργό Liveness Probe"]
startup -->|Πολλές αποτυχίες| restart1["Επανεκκίνηση Container"]
live -->|Επιτυχία| ready["Readiness Probe"]
live -->|Πολλές αποτυχίες| restart2["Επανεκκίνηση Container"]
ready -->|Ready| endpoints["Το EndpointSlice περιλαμβάνει το Pod"]
ready -->|Not Ready| noTraffic["Χωρίς κίνηση από το Service"]
Αντιπαράδειγμα: Μη χρησιμοποιείς το Liveness Probe αντί του Readiness Probe. Ένα ακατάλληλο Liveness Probe μπορεί να οδηγήσει μια υγιή αλλά αργή εφαρμογή σε επαναλαμβανόμενες επανεκκινήσεις.
4.7 Ομαλός τερματισμός
Όταν τερματίζεται ένα Pod, η δρομολόγηση της κυκλοφορίας, ο χειρισμός των Signals και το terminationGracePeriodSeconds πρέπει να λειτουργούν συντονισμένα.
sequenceDiagram
participant API as API Server
participant EP as EndpointSlice Controller
participant K as kubelet
participant APP as App Container
participant SVC as Κίνηση Service
API->>EP: Το Pod λαμβάνει deletionTimestamp
EP->>SVC: Αφαίρεση Endpoint από τη δρομολόγηση
API->>K: Τερματισμός Pod
K->>APP: Εκτέλεση preStop Hook αν υπάρχει
K->>APP: Αποστολή SIGTERM
APP->>APP: Ολοκλήρωση εκκρεμών Requests
K->>APP: SIGKILL μετά το Grace Period αν χρειάζεται
Σημείωση workshop: Προσομοίωσε ένα Rollout με μικρό Grace Period και παρατήρησε αν διακόπτονται Requests.
4.8 StatefulSet και σταθερή ταυτότητα
Το StatefulSet προορίζεται για Workloads που χρειάζονται σταθερά ονόματα, συγκεκριμένη σειρά εκκίνησης ή σταθερή αντιστοίχιση Volumes.
flowchart TD
sts["StatefulSet db"] --> pod0["db-0"]
sts --> pod1["db-1"]
sts --> pod2["db-2"]
pod0 --> pvc0["data-db-0"]
pod1 --> pvc1["data-db-1"]
pod2 --> pvc2["data-db-2"]
svc["Headless Service db"] --> pod0
svc --> pod1
svc --> pod2
dns0["db-0.db.namespace.svc"] --> pod0
dns1["db-1.db.namespace.svc"] --> pod1
dns2["db-2.db.namespace.svc"] --> pod2
Βασικός κανόνας: Ένα StatefulSet δεν εξασφαλίζει από μόνο του τη συνέπεια της εφαρμογής. Το Replication, το Quorum, το Backup και το Restore παραμένουν ευθύνες της εφαρμογής ή του Operator.
4.9 DaemonSet για λειτουργίες σε κάθε Node
Τα DaemonSets τοποθετούν ένα Pod σε κάθε επιλεγμένο Node. Είναι κατάλληλα για Node Agents, όχι για την τυπική οριζόντια κλιμάκωση μιας εφαρμογής.
flowchart LR
ds["DaemonSet"] --> node1["Node A"]
ds --> node2["Node B"]
ds --> node3["Node C"]
node1 --> agent1["Agent Pod"]
node2 --> agent2["Agent Pod"]
node3 --> agent3["Agent Pod"]
agent1 --> use1["Logs, Metrics, CNI ή ασφάλεια"]
agent2 --> use2["Logs, Metrics, CNI ή ασφάλεια"]
agent3 --> use3["Logs, Metrics, CNI ή ασφάλεια"]
Παραδείγματα: CNI Agent, συλλέκτης Logs, Node Exporter, Runtime Security Agent ή Storage Add-on για Nodes.
4.10 Job και CronJob
Τα Jobs εκτελούν εργασίες έως την ολοκλήρωσή τους. Τα CronJobs δημιουργούν Jobs σύμφωνα με ένα πρόγραμμα. Κανένα από τα δύο δεν προορίζεται για Services που εκτελούνται διαρκώς.
flowchart TD
cron["CronJob\nΠρόγραμμα"] --> job1["Job 2026-06-13 01:00"]
cron --> job2["Job 2026-06-14 01:00"]
job1 --> pod1["Pod πρώτη προσπάθεια"]
job1 --> pod2["Pod νέα προσπάθεια αν χρειάζεται"]
pod1 --> success["Succeeded"]
pod2 --> fail["Failed ή Succeeded"]
job2 --> pod3["Pod επόμενης εκτέλεσης"]
Σημεία ελέγχου: backoffLimit, activeDeadlineSeconds, concurrencyPolicy, startingDeadlineSeconds και διατήρηση παλαιών Jobs.
4.11 Κλιμάκωση Workload με HPA
Το Horizontal Pod Autoscaler παρακολουθεί Metrics και προσαρμόζει τον επιθυμητό αριθμό Replicas. Δεν υποκαθιστά σωστά Requests ή Load Tests.
flowchart LR
metrics["Metrics API\nCPU, Memory ή Custom Metrics"] --> hpa["Horizontal Pod Autoscaler"]
hpa --> decision{Χρειάζεται Scaling?}
decision -->|Μεγαλύτερο φορτίο| up["Αύξηση Replicas"]
decision -->|Μικρότερο φορτίο| down["Μείωση Replicas"]
up --> deploy["Scale Subresource του Deployment ή StatefulSet"]
down --> deploy
deploy --> pods["Περισσότερα ή λιγότερα Pods"]
Λειτουργική σημασία: Χωρίς Metrics Server ή κατάλληλο Metrics Adapter, το HPA δεν μπορεί να λειτουργήσει αξιόπιστα.
5. Services, DNS, Ingress και Gateway API
5.1 Δίκτυο Pod: Κάθε Pod έχει τη δική του IP
Το CNI Plugin παρέχει το δίκτυο και τη δρομολόγηση των Pods. Το Kubernetes ορίζει το μοντέλο δικτύου· η συγκεκριμένη υλοποίηση εξαρτάται από το CNI.
flowchart LR
subgraph nodeA["Node A"]
podA1["Pod A1\n10.244.1.10"]
podA2["Pod A2\n10.244.1.11"]
cniA["CNI"]
end
subgraph nodeB["Node B"]
podB1["Pod B1\n10.244.2.10"]
podB2["Pod B2\n10.244.2.11"]
cniB["CNI"]
end
podA1 --> cniA
cniA <--> cniB
cniB --> podB1
podA2 --> cniA
cniB --> podB2
Πρακτικός κανόνας: Οι IP διευθύνσεις των Pods μπορούν να δρομολογηθούν, αλλά δεν είναι σταθερές. Για σταθερή πρόσβαση χρησιμοποίησε Services.
5.2 Service, Selector και EndpointSlices
Ένα Service εντοπίζει Pods μέσω Labels και παρέχει σταθερό Service Discovery. Τα EndpointSlices περιέχουν τα πραγματικά Backends στα οποία μπορεί να δρομολογηθεί η κίνηση.
flowchart TD
svc["Service\nselector app=shop"] --> selector["Label Selector"]
selector --> pod1["Pod 1\napp=shop\nReady"]
selector --> pod2["Pod 2\napp=shop\nReady"]
selector --> pod3["Pod 3\napp=shop\nNotReady"]
pod1 --> eps["EndpointSlice"]
pod2 --> eps
pod3 -. Δεν είναι Ready .-> eps
eps --> dataplane["kube-proxy ή eBPF dataplane"]
dataplane --> client["Client μέσα στο Cluster"]
Ερώτηση για τον έλεγχο: Αν ένα Service δεν λειτουργεί, μην ελέγχεις μόνο το ίδιο. Έλεγξε τα Labels, τους Selectors, την ετοιμότητα των Pods και τα EndpointSlices.
5.3 Σύγκριση τύπων Service
Οι τύποι Service διαφέρουν ως προς την έκταση στην οποία εκθέτουν μια υπηρεσία.
flowchart TD
svc["Service"] --> clusterip["ClusterIP\nΕσωτερικά στο Cluster"]
svc --> nodeport["NodePort\nΘύρα σε κάθε Node"]
svc --> lb["LoadBalancer\nΕξωτερικός Load Balancer"]
svc --> external["ExternalName\nDNS alias"]
clusterip --> internal["Κίνηση από Pod προς Service"]
nodeport --> node["Ο Client χρησιμοποιεί την IP και τη θύρα του Node"]
lb --> cloud["Cloud ή MetalLB παρέχει εξωτερική διεύθυνση"]
external --> dns["Επίλυση ονόματος τύπου CNAME"]
Κανόνας σχεδιασμού: Χρησιμοποίησε το ClusterIP ως προεπιλογή. Για ελεγχόμενη εξωτερική πρόσβαση χρησιμοποίησε LoadBalancer, Gateway ή Ingress. Το NodePort αποτελεί συχνά λεπτομέρεια της υποδομής και όχι τον κύριο τρόπο δημοσίευσης της υπηρεσίας.
5.4 Επίλυση DNS μέσα στο Cluster
Το CoreDNS παρέχει Service Discovery μέσω DNS. Τα προβλήματα DNS εμφανίζονται συχνά ως σφάλματα εφαρμογής, ακόμη και όταν το Service και τα Pods φαίνονται σωστά.
sequenceDiagram
participant APP as App Pod
participant DNS as CoreDNS
participant API as API Server
participant SVC as Service
participant EP as EndpointSlice
APP->>DNS: Επίλυση shop.demo.svc.cluster.local
DNS->>API: Δεδομένα Service και Endpoint από Cache/API
API-->>DNS: IP του Service ή δεδομένα Endpoint
DNS-->>APP: Απάντηση DNS
APP->>SVC: Σύνδεση στην IP του Service
SVC->>EP: Δρομολόγηση προς κατάλληλο Pod
Σημείωση για το Troubleshooting: Δοκίμασε το DNS από ένα Debug Pod στο ίδιο Namespace. Έλεγξε τόσο το σύντομο όνομα όσο και το FQDN.
5.5 Διαδρομή Ingress για HTTP και HTTPS
Το Ingress είναι ένα API Object, αλλά λειτουργεί μόνο όταν εκτελείται ένας Ingress Controller. Ο Controller μετατρέπει τους κανόνες σε συγκεκριμένη ρύθμιση του Proxy.
flowchart LR
client["Browser ή API Client"] --> dns["DNS"]
dns --> lb["Load Balancer"]
lb --> controller["Ingress Controller"]
controller --> ingress["Κανόνες Ingress\nHost και Path"]
ingress --> service["Service"]
service --> endpoints["EndpointSlices"]
endpoints --> pod1["Pod A"]
endpoints --> pod2["Pod B"]
cert["TLS Secret ή cert-manager"] --> controller
Έλεγξε την αλυσίδα: DNS → Load Balancer → Ingress Controller → IngressClass → κανόνας Ingress → Service → EndpointSlice → ετοιμότητα Pod.
5.6 Gateway API: δρομολόγηση με διακριτούς ρόλους
Το Gateway API διαχωρίζει σαφέστερα τις ευθύνες της υποδομής από τη δρομολόγηση των εφαρμογών σε σχέση με το κλασικό Ingress.
flowchart TD
infra["Ομάδα πλατφόρμας"] --> gatewayClass["GatewayClass"]
infra --> gateway["Gateway\nListener, διεύθυνση, TLS"]
appteam["Ομάδα εφαρμογής"] --> route["HTTPRoute, GRPCRoute ή TCPRoute"]
route --> service["Service"]
service --> pods["Pods"]
gatewayClass --> controller["Gateway Controller"]
gateway --> controller
route --> controller
controller --> dataplane["Proxy ή Load Balancer"]
dataplane --> service
Πρακτικός κανόνας: Το Gateway API είναι ιδιαίτερα χρήσιμο όταν οι ομάδες πλατφόρμας και εφαρμογών έχουν διαφορετικές αρμοδιότητες.
5.7 NetworkPolicy: προεπιλεγμένη άρνηση και επιτρεπόμενη κίνηση
Τα NetworkPolicies επιτρέπουν ή αποκλείουν την κίνηση των Pods. Εφαρμόζονται μόνο αν το Network Plugin υποστηρίζει την επιβολή NetworkPolicy.
flowchart TD
ns["Namespace demo"] --> defaultDeny["Default Deny Policy"]
defaultDeny --> pod["Pod app=api"]
client["Pod app=frontend"] -->|Επιτρέπεται TCP 8080| pod
db["Pod app=db"] -. Δεν επιτρέπεται .-> pod
internet["Εξωτερική κίνηση"] -. Δεν επιτρέπεται .-> pod
policy["NetworkPolicy\nPodSelector app=api"] --> ingress["Κανόνες Ingress"]
ingress --> client
Anti-pattern: Ένα NetworkPolicy χωρίς υποστήριξη από το CNI δημιουργεί ψευδή αίσθηση ασφάλειας. Δοκίμασε στην πράξη αν οι κανόνες εφαρμόζονται.
5.8 Έλεγχος εξόδου
Οι κανόνες Egress περιορίζουν τους προορισμούς με τους οποίους μπορεί να συνδεθεί ένα Pod. Αυτό έχει σημασία για την αποτροπή διαρροής δεδομένων, την προστασία της εφοδιαστικής αλυσίδας και τον έλεγχο των εξαρτήσεων.
flowchart LR
pod["App Pod"] --> policy["Egress NetworkPolicy"]
policy -->|Επιτρέπεται| dns["CoreDNS TCP/UDP 53"]
policy -->|Επιτρέπεται| api["Εσωτερικό API Service"]
policy -. Αποκλείεται .-> internet["Οποιοσδήποτε προορισμός στο Internet"]
policy -. Αποκλείεται .-> metadata["Cloud Metadata Service"]
Άσκηση workshop: Δημιούργησε μια πολιτική Egress με προεπιλεγμένη άρνηση και επίτρεψε μόνο το DNS και την υπηρεσία προορισμού. Παρατήρησε τις παρενέργειες.
5.9 Service Mesh στο πλαίσιο
Ένα Service Mesh προσθέτει διαχείριση κίνησης, mTLS, Telemetry και Policies στο Kubernetes. Δεν αντικαθιστά τα Services, Deployments ή RBAC.
flowchart TD
client["Client Pod"] --> sidecarA["Sidecar Proxy A"]
sidecarA --> mesh["Mesh Control Plane"]
sidecarA --> sidecarB["Sidecar Proxy B"]
sidecarB --> server["Server Pod"]
mesh --> certs["Certificates και ταυτότητες"]
mesh --> routing["Κανόνες δρομολόγησης"]
mesh --> telemetry["Metrics και Traces"]
k8s["Kubernetes API"] --> mesh
Πλαίσιο χρήσης: Ένα Service Mesh αυξάνει τόσο τις δυνατότητες όσο και την πολυπλοκότητα της πλατφόρμας. Χρησιμοποίησέ το όταν έχεις σαφείς απαιτήσεις και μπορείς να το λειτουργήσεις.
6. Configuration, Secrets και Images
6.1 ConfigMaps: διαχωρισμός ρυθμίσεων και Image
Τα ConfigMaps αποσυνδέουν τις ρυθμίσεις από το Container Image. Μπορείς να τα χρησιμοποιήσεις ως μεταβλητές περιβάλλοντος ή ως αρχεία που προσαρτώνται μέσω Volumes.
flowchart TD
cm["ConfigMap"] --> env["Μεταβλητές περιβάλλοντος"]
cm --> volume["Προσάρτηση Volume ως αρχείου"]
deploy["Deployment"] --> pod["Pod"]
pod --> env
pod --> volume
image["Container Image"] --> pod
change["Το ConfigMap άλλαξε"] --> effect{Πώς προσαρτάται?}
effect -->|Env| restart["Απαιτείται επανεκκίνηση Pod"]
effect -->|Volume| refresh["Το αρχείο μπορεί να ενημερωθεί"]
Πρακτικός κανόνας: Η αλλαγή ενός ConfigMap δεν επαναφορτώνει απαραίτητα την εφαρμογή. Σχεδίασε συνειδητά τον μηχανισμό επαναφόρτωσης ή το Rollout.
6.2 Secrets: διαδρομή πρόσβασης και όρια προστασίας
Τα Kubernetes Secrets είναι API Objects. Το Base64 είναι κωδικοποίηση, όχι κρυπτογράφηση. Η προστασία εξαρτάται από το RBAC, την κρυπτογράφηση κατά την αποθήκευση, την προστασία των Nodes και τη διαχείριση των Secrets.
flowchart TD
user["Εξουσιοδοτημένη ταυτότητα ή Controller"] --> api["API Server"]
api --> rbac["Έλεγχος RBAC"]
rbac --> secret["Secret Object"]
secret --> etcd["etcd\nΠροαιρετικό Encryption at Rest"]
secret --> kubelet["kubelet στο Node προορισμού"]
kubelet --> pod["Pod Volume ή Env"]
pod --> app["Η εφαρμογή διαβάζει το Secret"]
attacker["Υπερβολικά δικαιώματα"] -. get/list/watch Secrets .-> secret
Κανόνας λειτουργίας: Όποιος μπορεί να διαβάσει Secrets αποκτά συχνά πρόσβαση και στα συστήματα που αυτά προστατεύουν. Παραχώρησε δικαιώματα ανάγνωσης Secrets πολύ πιο περιορισμένα από τα γενικά δικαιώματα ανάγνωσης.
6.3 Εξωτερικά συστήματα διαχείρισης Secrets
Πολλές πλατφόρμες συγχρονίζουν Secrets από το Vault, από Cloud Secret Managers ή από Git Repositories κρυπτογραφημένα με SOPS. Το Kubernetes παραμένει η πλατφόρμα εκτέλεσης, αλλά δεν είναι απαραίτητα η αυθεντική πηγή των Secrets.
flowchart LR
source["Εξωτερική πηγή Secrets\nVault, Cloud Secret Manager ή SOPS"] --> controller["External Secrets Controller ή GitOps"]
controller --> api["Kubernetes API"]
api --> k8ssecret["Kubernetes Secret"]
k8ssecret --> pod["Pod"]
rotate["Rotation"] --> source
source --> audit["Audit και έλεγχος πρόσβασης"]
Απόφαση: Όρισε ποιο σύστημα αποτελεί την αυθεντική πηγή, πώς γίνεται το Rotation και ποιος έχει πρόσβαση στην πηγή, στο Kubernetes Secret και στο Pod.
6.4 Image Pull και πρόσβαση στο Registry
Το ImagePullBackOff οφείλεται συχνά σε λανθασμένα ονόματα Images ή Tags, ελλιπή δικαιώματα στο Registry, προβλήματα δικτύου ή απουσία των απαραίτητων Pull Secrets.
sequenceDiagram
participant K as kubelet
participant R as Container Runtime
participant REG as Registry
participant P as Pod
K->>R: Λήψη Image
R->>REG: Αίτημα για Manifest και Layers
REG-->>R: Επιτρέπεται ή απορρίπτεται
R-->>K: Το Image είναι διαθέσιμο ή υπάρχει σφάλμα
K->>P: Εκκίνηση Container
P-->>K: Αναφορά Status
Σημεία ελέγχου: Όνομα Image, Tag, αρχιτεκτονική, πρόσβαση στο Registry, TLS, Authentication, imagePullSecrets, Quotas και Rate Limits.
6.5 Εφοδιαστική αλυσίδα των Images
Ένα Image κατάλληλο για Production δεν δημιουργείται τη στιγμή του Deployment. Χρειάζεται ελεγχόμενη διαδικασία Build, Scans, Signatures και Artifacts με δυνατότητα ιχνηλάτησης.
flowchart LR
code["Πηγαίος κώδικας"] --> build["Build Pipeline"]
build --> test["Tests"]
test --> scan["Scan του Image και των Dependencies"]
scan --> sbom["SBOM"]
sbom --> sign["Signature"]
sign --> registry["Registry"]
registry --> admission["Admission Policy"]
admission --> cluster["Deployment στο Cluster"]
Ερώτηση ελέγχου: Ποια Policy εμποδίζει μη δοκιμασμένα ή ανυπόγραφα Images να εισέλθουν στα Production Namespaces;
7. Storage και διατήρηση δεδομένων
7.1 Βασικό μοντέλο Storage
Τα Pods είναι προσωρινά. Η διατήρηση δεδομένων υλοποιείται μέσω Volumes, PVCs, PVs, StorageClasses και CSI Drivers.
flowchart TD
pod["Pod"] --> volume["Volume Mount"]
volume --> pvc["PersistentVolumeClaim"]
pvc --> pv["PersistentVolume"]
pv --> backend["Storage Backend"]
sc["StorageClass"] --> pvc
csi["CSI Driver"] --> pv
csi --> backend
Πρακτικός κανόνας: Η εφαρμογή ζητά Storage μέσω ενός PVC. Η πλατφόρμα καθορίζει το StorageClass, το Provisioning, την απόδοση, τα Backups και τον κύκλο ζωής.
7.2 Δυναμικό Provisioning Volumes
Με το δυναμικό Provisioning, ένας CSI Provisioner δημιουργεί το κατάλληλο Volume στο Storage Backend όταν δημιουργείται ένα PVC.
sequenceDiagram
participant U as Χρήστης
participant API as API Server
participant PVC as PVC Controller
participant CSI as CSI Provisioner
participant BE as Storage Backend
participant POD as Pod
U->>API: Δημιουργία PVC
API-->>PVC: Νέο Claim
PVC->>CSI: Αίτημα Volume
CSI->>BE: Δημιουργία Storage Volume
BE-->>CSI: Το Volume δημιουργήθηκε
CSI->>API: Δημιουργία και Binding του PV
POD->>API: Εκκίνηση Pod με PVC
API-->>POD: Το PVC έχει δεσμευτεί
Σημείωση για το Troubleshooting: Αν ένα PVC παραμένει σε κατάσταση Pending, έλεγξε το StorageClass, τον Provisioner, τα Events, τα Quotas, τις Zones και τα Logs του CSI Controller.
7.3 Binding Modes και Zones
Ένα Volume μπορεί να δεσμευτεί αμέσως ή κατά το Scheduling. Η διαφορά έχει σημασία όταν το Storage συνδέεται με συγκεκριμένες Availability Zones.
flowchart TD
pvc["PVC"] --> mode{volumeBindingMode}
mode --> immediate["Immediate"]
mode --> wait["WaitForFirstConsumer"]
immediate --> pv1["Άμεση δημιουργία PV"]
pv1 --> risk["Η Zone ίσως δεν ταιριάζει με το Node"]
wait --> pod["Δημιουργία Pod"]
pod --> scheduler["Ο Scheduler επιλέγει Node και Zone"]
scheduler --> pv2["PV στην κατάλληλη Zone"]
Κανόνας σχεδιασμού: Για Cloud Storage που περιορίζεται σε συγκεκριμένη Zone, το WaitForFirstConsumer είναι συχνά η πιο αξιόπιστη επιλογή.
7.4 StatefulSet με volumeClaimTemplates
Τα StatefulSets δημιουργούν ξεχωριστό PVC για κάθε Pod. Όταν διαγράφεται ένα Pod, το Volume συνήθως διατηρείται.
flowchart TD
sts["StatefulSet postgres"] --> template["volumeClaimTemplates"]
template --> pvc0["data-postgres-0"]
template --> pvc1["data-postgres-1"]
template --> pvc2["data-postgres-2"]
pvc0 --> pv0["PV 0"]
pvc1 --> pv1["PV 1"]
pvc2 --> pv2["PV 2"]
pod0["postgres-0"] --> pvc0
pod1["postgres-1"] --> pvc1
pod2["postgres-2"] --> pvc2
Ερώτηση για τον έλεγχο: Τι συμβαίνει στα PVCs όταν διαγράφεις το StatefulSet; Μη βασίζεσαι σε υποθέσεις. Έλεγξε την Retention Policy και τη συμπεριφορά της πλατφόρμας.
7.5 Components του CSI
Το CSI διαχωρίζει το Kubernetes από τα συγκεκριμένα Storage Backends. Τα Controller Components διαχειρίζονται τα Volumes, ενώ τα Node Components τα προσαρτούν στα Nodes.
flowchart TD
subgraph control["Επίπεδο CSI Controller"]
provisioner["external-provisioner"]
attacher["external-attacher"]
resizer["external-resizer"]
snapshotter["external-snapshotter"]
csiController["CSI Controller Plugin"]
end
subgraph node["Επίπεδο CSI Node"]
kubelet["kubelet"]
registrar["node-driver-registrar"]
csiNode["CSI Node Plugin"]
mount["Προσάρτηση στο Pod"]
end
provisioner --> csiController
attacher --> csiController
resizer --> csiController
snapshotter --> csiController
csiController --> backend["Storage Backend"]
kubelet --> registrar
kubelet --> csiNode
csiNode --> mount
mount --> pod["Pod"]
Λειτουργική σημασία: Ένα πρόβλημα Storage μπορεί να προέρχεται από το PVC, το PV, το StorageClass, τον CSI Controller, το CSI Node Plugin, το Backend ή την προσάρτηση στο Node.
7.6 Backup και Restore των Workloads
Τα Kubernetes Manifests από μόνα τους δεν αρκούν για εφαρμογές με μόνιμα δεδομένα. Χρειάζεσαι επίσης Backups των δεδομένων και δοκιμές Restore.
flowchart LR
manifests["Manifests και Helm Values"] --> git["Git ή Artifact Repository"]
pvdata["Μόνιμα δεδομένα"] --> backup["Backup ή Snapshot"]
etcd["Κατάσταση Cluster"] --> etcdbackup["etcd Backup"]
git --> restore["Διαδικασία Restore"]
backup --> restore
etcdbackup --> restore
restore --> validation["Validation\nδεδομένα, εφαρμογή, Service, δικαιώματα"]
Πρακτικός κανόνας: Ένα Backup είναι αξιόπιστο μόνο όταν έχεις δοκιμάσει το Restore και έχεις ελέγξει το αποτέλεσμα από την πλευρά της εφαρμογής.
8. Scheduling, πόροι και διαθεσιμότητα
8.1 Ροή Scheduling
Ο Scheduler επιλέγει ένα Node με βάση τους διαθέσιμους πόρους, τους περιορισμούς, τις Policies και την τρέχουσα κατάσταση του Cluster.
sequenceDiagram
participant API as API Server
participant S as Scheduler
participant N as Nodes
participant K as kubelet
API-->>S: Ο Scheduler βλέπει Pod χωρίς nodeName
S->>N: Φιλτράρισμα Nodes
S->>N: Αξιολόγηση Nodes
S->>API: Binding του Pod σε Node
API-->>K: Το kubelet του Node βλέπει το Pod
K->>K: Προετοιμασία και εκκίνηση Containers
K->>API: Αναφορά κατάστασης Pod
Ερώτηση για τον έλεγχο: Ένα Pod σε κατάσταση Pending συχνά δεν έχει φτάσει καν στο kubelet. Ξεκίνα από τα Events του Scheduler.
8.2 Requests, Limits και QoS
Τα Requests καθοδηγούν το Scheduling. Τα Limits περιορίζουν την κατανάλωση πόρων κατά την εκτέλεση. Μαζί καθορίζουν τις κλάσεις QoS που έχουν σημασία όταν οι πόροι πιέζονται.
flowchart TD
container["Πόροι Container"] --> requests["Requests"]
container --> limits["Limits"]
requests --> scheduling["Ο Scheduler προγραμματίζει τη χωρητικότητα"]
limits --> runtime["Το Runtime περιορίζει την κατανάλωση"]
requests --> qos{Κλάση QoS}
limits --> qos
qos --> guaranteed["Guaranteed"]
qos --> burstable["Burstable"]
qos --> besteffort["BestEffort"]
besteffort --> eviction["Μεγαλύτερος κίνδυνος Eviction"]
Κανόνας σχεδιασμού: Κάθε Production Workload χρειάζεται ρεαλιστικά Requests. Χωρίς αυτά, το Kubernetes δεν μπορεί να προγραμματίσει σωστά τη διαθέσιμη χωρητικότητα.
8.3 Node Affinity και Pod Anti-Affinity
Οι κανόνες Affinity ελέγχουν την τοποθέτηση των Pods. Χρησιμοποίησε υποχρεωτικούς κανόνες με φειδώ, γιατί μπορούν να αφήσουν Pods σε κατάσταση Pending χωρίς λόγο.
flowchart TD
pod["Pod"] --> required["requiredDuringScheduling"]
pod --> preferred["preferredDuringScheduling"]
required --> nodeA["Μόνο Nodes με Label disk=ssd"]
preferred --> nodeB["Προτίμηση Zone eu-central-1a"]
anti["Pod Anti-Affinity"] --> spread["Όχι δίπλα σε Pod της ίδιας εφαρμογής"]
spread --> nodes["Κατανομή σε Nodes ή Zones"]
Σημείωση workshop: Ζήτησε από τους συμμετέχοντες να ορίσουν έναν υποχρεωτικό κανόνα Affinity που δεν ικανοποιεί κανένα Node. Στη συνέχεια ας ερμηνεύσουν τα Events.
8.4 Taints και Tolerations
Τα Taints αποτρέπουν την τοποθέτηση Pods σε ένα Node. Τα Tolerations επιτρέπουν σε Pods να εκτελεστούν σε Nodes με αντίστοιχα Taints, αλλά δεν εγγυώνται ότι θα τοποθετηθούν εκεί.
flowchart LR
node["Node με Taint\ndedicated=gpu:NoSchedule"] --> barrier["Αποκλεισμός"]
podA["Pod χωρίς Toleration"] -. Δεν τοποθετείται .-> barrier
podB["Pod με κατάλληλο Toleration"] --> barrier
barrier --> scheduler["Ο Scheduler μπορεί να εξετάσει το Node"]
scheduler --> node
Πρακτικός κανόνας: Ένα Toleration σημαίνει «μπορεί να εκτελεστεί εκεί», όχι «πρέπει να εκτελεστεί εκεί». Για στοχευμένη τοποθέτηση συνδύασε Taints και Tolerations με Node Affinity.
8.5 Topology Spread Constraints
Τα Topology Spread Constraints κατανέμουν τα Pods σε διαφορετικά Failure Domains, όπως Nodes, Zones ή Racks.
flowchart TD
deploy["Deployment replicas=6"] --> tsc["Topology Spread Constraint\ntopologyKey=zone"]
tsc --> zoneA["Zone A\n2 Pods"]
tsc --> zoneB["Zone B\n2 Pods"]
tsc --> zoneC["Zone C\n2 Pods"]
zoneA --> nodeA1["Node A1"]
zoneB --> nodeB1["Node B1"]
zoneC --> nodeC1["Node C1"]
Ερώτηση σχεδιασμού: Πρέπει το Kubernetes να συνεχίσει το Scheduling όταν τα Pods κατανέμονται άνισα ή να το αποκλείσει; Αυτή τη συμπεριφορά την ορίζεις με το whenUnsatisfiable.
8.6 PodDisruptionBudget
Ένα PDB προστατεύει από προγραμματισμένες διακοπές, όπως Node Drains, Upgrades ή χειροκίνητα Evictions. Δεν προστατεύει από βλάβη ενός Node ή από Crashes.
flowchart LR
deploy["Deployment replicas=3"] --> pdb["PDB minAvailable=2"]
drain["kubectl drain node-a"] --> eviction1["Eviction Pod 1"]
eviction1 --> allowed{Θα παραμείνουν διαθέσιμα τουλάχιστον 2 Pods?}
allowed -->|Ναι| evict["Το Eviction επιτρέπεται"]
allowed -->|Όχι| block["Το Eviction αποκλείεται"]
pdb --> allowed
Λειτουργική σημασία: Πολύ αυστηρά PDBs μπορούν να μπλοκάρουν Upgrades. Πολύ χαλαρά PDBs δεν προστατεύουν επαρκώς την εφαρμογή.
8.7 Cluster Autoscaler και Pending Pods
Ο Cluster Autoscaler ανταποκρίνεται σε Pods που δεν μπορούν να τοποθετηθούν λόγω ανεπαρκούς χωρητικότητας των Nodes. Δεν διορθώνει λανθασμένο Affinity, Taints ή προβλήματα PVC.
flowchart TD
pod["Pod Pending"] --> reason{Γιατί είναι Pending?}
reason -->|Ανεπαρκές CPU ή Memory| ca["Ο Cluster Autoscaler ελέγχει το Node Group"]
reason -->|Αδύνατο Affinity| fix1["Διόρθωση Manifest ή Labels"]
reason -->|Λείπει Toleration| fix2["Έλεγχος σχεδιασμού Toleration και Taint"]
reason -->|Ασυμφωνία Storage Zone| fix3["Έλεγχος StorageClass και Binding"]
ca --> scale["Προσθήκη νέου Node"]
scale --> scheduler["Ο Scheduler τοποθετεί το Pod"]
Πρακτικός κανόνας: Το Autoscaling δεν αντικαθιστά τον σωστό σχεδιασμό του Scheduling.
8.8 ResourceQuotas και LimitRanges
Τα Namespaces μπορούν να περιορίζονται με ResourceQuotas και LimitRanges. Έτσι προστατεύεται η χωρητικότητα της πλατφόρμας και εφαρμόζονται ελάχιστα πρότυπα.
flowchart TD
ns["Namespace team-a"] --> quota["ResourceQuota"]
ns --> limitrange["LimitRange"]
quota --> max["Μέγιστο σύνολο\nCPU, Memory, Pods, PVCs"]
limitrange --> defaults["Προεπιλεγμένα Requests και Limits"]
deploy["Νέο Workload"] --> admission["Έλεγχος Admission"]
max --> admission
defaults --> admission
admission -->|Εντός ορίων| create["Το Resource δημιουργείται"]
admission -->|Παραβίαση ορίου| reject["Το Request απορρίπτεται"]
Ερώτηση ελέγχου: Διαθέτει κάθε Team Namespace Quotas, προεπιλεγμένα Requests και σαφή διαδικασία για αύξηση της χωρητικότητας;
9. Ασφάλεια και έλεγχος πρόσβασης
9.1 Αλυσίδα ελέγχων ασφαλείας
Η ασφάλεια στο Kubernetes αποτελείται από διαδοχικούς ελέγχους. Ένας μόνο μηχανισμός δεν αρκεί.
flowchart LR
request["API Request"] --> authn["Authentication"]
authn --> authz["Authorization\nRBAC ή Webhook"]
authz --> admission["Admission\nValidation και Mutation"]
admission --> etcd["Αποθήκευση στο etcd"]
etcd --> kubelet["Εκτέλεση από το kubelet"]
kubelet --> runtime["Απομόνωση από το Runtime"]
runtime --> network["NetworkPolicy"]
network --> observe["Audit, Logs, Runtime Detection"]
Πρακτικός κανόνας: Το RBAC απαντά «μπορεί αυτή η ταυτότητα να εκτελέσει αυτή την ενέργεια στο API;». Το Pod Security απαντά «επιτρέπεται αυτή η προδιαγραφή Pod;». Το NetworkPolicy απαντά «ποια κίνηση μεταξύ Pods επιτρέπεται;».
9.2 Μοντέλο σχέσεων RBAC
Το RBAC συνδέει Subjects με Roles. Τα Roles περιέχουν κανόνες και τα Bindings ορίζουν τη σύνδεση.
flowchart TD
subject["Subject\nUser, Group ή ServiceAccount"] --> binding["RoleBinding ή ClusterRoleBinding"]
binding --> role["Role ή ClusterRole"]
role --> rule1["apiGroups"]
role --> rule2["resources"]
role --> rule3["verbs"]
rule3 --> examples["get, list, watch, create, update, patch, delete"]
binding --> scope{Πεδίο ισχύος}
scope --> ns["Namespace"]
scope --> cluster["Σε όλο το Cluster"]
Anti-pattern: Η παραχώρηση cluster-admin σε CI/CD, Developers ή Workloads δίνει σχεδόν πάντα υπερβολικά ευρεία δικαιώματα.
9.3 ServiceAccount και ταυτότητα Workload
Τα Pods χρησιμοποιούν ServiceAccounts για την επικοινωνία με το Kubernetes API. Τα δικαιώματα αποδίδονται μέσω RBAC Bindings και όχι μέσω του ονόματος του Pod.
flowchart LR
pod["Pod"] --> sa["ServiceAccount"]
sa --> token["Bound ServiceAccount Token"]
token --> api["API Server"]
api --> rbac["RBAC"]
rbac --> allowed["Επιτρεπόμενες ενέργειες API"]
rbac --> denied["Απορριπτόμενες ενέργειες API"]
Εντολή ελέγχου: kubectl auth can-i --as system:serviceaccount:<namespace>:<serviceaccount> <verb> <resource>.
9.4 Admission Control και εφαρμογή Policies
Οι Admission Controllers ελέγχουν ή τροποποιούν Objects πριν αποθηκευτούν. Έτσι μπορείς να εφαρμόζεις τα πρότυπα της πλατφόρμας.
sequenceDiagram
participant U as Χρήστης ή CI/CD
participant API as API Server
participant M as Mutating Admission
participant V as Validating Admission
participant P as Policy Engine
participant E as etcd
U->>API: Δημιουργία Pod
API->>M: Προσθήκη Defaults ή Sidecars
M-->>API: Τροποποιημένο Object
API->>V: Validation του Object
V->>P: Έλεγχος Policy
P-->>V: Αποδοχή ή απόρριψη
V-->>API: Αποτέλεσμα
API->>E: Αποθήκευση αν επιτρέπεται
Παραδείγματα: Pod Security Admission, ValidatingAdmissionPolicy, Kyverno, Gatekeeper, Image Policies και πρότυπα για Namespaces.
9.5 Pod Security Standards
Τα Pod Security Standards οργανώνουν τις απαιτήσεις ασφαλείας των Pods σε επίπεδα. Η εφαρμογή τους γίνεται συχνά μέσω Namespace Labels και Pod Security Admission.
flowchart TD
ns["Namespace"] --> labels["pod-security.kubernetes.io labels"]
labels --> privileged["Privileged\nΕλάχιστοι περιορισμοί"]
labels --> baseline["Baseline\nΒασικοί περιορισμοί"]
labels --> restricted["Restricted\nΑυστηρότερη προστασία"]
pod["Νέο Pod"] --> admission["Pod Security Admission"]
labels --> admission
admission -->|Συμμορφώνεται| allowed["Το Pod γίνεται αποδεκτό"]
admission -->|Παραβιάζει Policy| denied["Το Pod απορρίπτεται ή εκδίδεται Warning"]
Σημείωση workshop: Ξεκίνα με warn και audit πριν εφαρμόσεις το restricted στα Production Namespaces.
9.6 SecurityContext στο Pod
Το SecurityContext ορίζει τις επιλογές ασφαλείας του Linux και του Runtime σε επίπεδο Pod ή Container.
flowchart TD
pod["Προδιαγραφή Pod"] --> podctx["Pod SecurityContext"]
pod --> containers["Containers"]
containers --> cctx["Container SecurityContext"]
podctx --> fs["fsGroup, runAsUser, runAsNonRoot"]
cctx --> caps["Αφαίρεση ή προσθήκη Capabilities"]
cctx --> priv["privileged"]
cctx --> ro["readOnlyRootFilesystem"]
cctx --> seccomp["seccompProfile"]
cctx --> allow["allowPrivilegeEscalation"]
Κανόνας ελέγχου: Ως προεπιλογή, χρησιμοποίησε non-root εκτέλεση, απενεργοποίησε το Privilege Escalation, αφαίρεσε περιττά Capabilities και προτίμησε read-only Root Filesystem και κατάλληλο Seccomp Profile.
9.7 Απομόνωση Tenants με Namespaces
Τα Namespaces από μόνα τους δεν αποτελούν πλήρες όριο ασφαλείας. Σε συνδυασμό με RBAC, Quotas, NetworkPolicies, Pod Security, Admission και σαφώς διαχωρισμένες ευθύνες μπορούν να στηρίξουν ένα λειτουργικό μοντέλο Multi-Tenancy.
flowchart TD
cluster["Cluster"] --> nsA["Namespace ομάδας A"]
cluster --> nsB["Namespace ομάδας B"]
nsA --> rbacA["RBAC ομάδας A"]
nsA --> quotaA["Quota και LimitRange"]
nsA --> netA["NetworkPolicies"]
nsA --> pssA["Pod Security"]
nsB --> rbacB["RBAC ομάδας B"]
nsB --> quotaB["Quota και LimitRange"]
nsB --> netB["NetworkPolicies"]
nsB --> pssB["Pod Security"]
admission["Admission Policies για όλο το Cluster"] --> nsA
admission --> nsB
Απόφαση: Για πολύ διαφορετικές απαιτήσεις ασφαλείας ή Compliance, ένα ξεχωριστό Cluster μπορεί να είναι καταλληλότερο από ένα κοινό Multi-Tenant Cluster.
9.8 Audit Logs και Runtime Detection
Τα Audit Logs δείχνουν τη δραστηριότητα στο API. Το Runtime Detection δείχνει τη συμπεριφορά μέσα στα Containers που εκτελούνται και πάνω στα Nodes.
flowchart LR
actor["Χρήστης, CI/CD ή Workload"] --> api["API Server"]
api --> audit["Audit Log"]
pod["Pod που εκτελείται"] --> runtime["Runtime Events"]
node["Node"] --> syscall["System Calls και συμπεριφορά διεργασιών"]
runtime --> detection["Falco, Tetragon ή EDR"]
syscall --> detection
audit --> siem["SIEM ή πλατφόρμα Logs"]
detection --> siem
siem --> alert["Ειδοποίηση ασφαλείας"]
Πρακτικός κανόνας: Το API Audit δείχνει ποιος άλλαξε κάτι στο Kubernetes. Το Runtime Detection δείχνει τι συμβαίνει μέσα στο Container που εκτελείται ή στο Node.
10. Observability και λειτουργία
10.1 Τρεις τύποι σημάτων: Metrics, Logs και Traces
Το Observability συνδυάζει διαφορετικούς τύπους σημάτων. Τα Events και η κατάσταση του Kubernetes συμπληρώνουν αυτή την εικόνα.
flowchart TD
workload["Workload"] --> metrics["Metrics"]
workload --> logs["Logs"]
workload --> traces["Traces"]
k8s["Kubernetes API"] --> status["Status και Conditions"]
k8s --> events["Events"]
metrics --> dash["Dashboards και Alerts"]
logs --> search["Αναζήτηση Logs"]
traces --> flow["Διαδρομές Requests"]
status --> triage["Triage"]
events --> triage
Κανόνας λειτουργίας: Ξεκίνα το Triage συνήθως από την κατάσταση και τα Events, αντί να διαβάζεις Logs χωρίς συγκεκριμένο ερώτημα.
10.2 Μοντέλο Prometheus μέσα στο Cluster
Το Prometheus συλλέγει Metrics από εφαρμογές, Nodes και Kubernetes Components. Το Service Discovery χρησιμοποιεί συνήθως Kubernetes Labels και Endpoints.
flowchart TD
prom["Prometheus"] --> sd["Kubernetes Service Discovery"]
sd --> pods["App Pods με /metrics"]
sd --> nodes["Node Exporter"]
sd --> kubelet["kubelet / cAdvisor"]
sd --> ksm["kube-state-metrics"]
prom --> rules["Κανόνες Alerts"]
rules --> alertmanager["Alertmanager"]
prom --> grafana["Grafana Dashboards"]
Ερώτηση ελέγχου: Μετράς μόνο την κατάσταση της υποδομής ή και SLO Signals που έχουν σημασία για την υπηρεσία, όπως Error Rate, Latency και Throughput;
10.3 Ροή συλλογής Logs
Τα Containers συνήθως γράφουν Logs στα stdout και stderr. Agents πάνω στα Nodes συλλέγουν αυτά τα Logs και τα προωθούν σε μια κεντρική πλατφόρμα.
flowchart LR
app["App Container"] --> stdout["stdout και stderr"]
stdout --> nodefiles["Αρχεία Logs στο Node"]
nodefiles --> agent["Log Agent ως DaemonSet"]
agent --> buffer["Buffer και Parsing"]
buffer --> backend["Loki, Elasticsearch ή Cloud Logging"]
backend --> query["Αναζήτηση και Dashboards"]
Anti-pattern: Αν γράφεις Logs μόνο στο Filesystem του Container, κινδυνεύεις να χάσεις κρίσιμα διαγνωστικά στοιχεία όταν επανεκκινηθεί το Pod ή παρουσιαστεί πρόβλημα στο Node.
10.4 Tracing μεταξύ Services
Το Tracing κάνει ορατή τη διαδρομή ενός Request ανάμεσα σε πολλά Services.
sequenceDiagram
participant C as Client
participant FE as Frontend
participant API as Backend API
participant DB as Database
participant OTEL as OpenTelemetry Collector
C->>FE: Request με Trace Context
FE->>OTEL: Αποστολή Span
FE->>API: Προώθηση Request
API->>OTEL: Αποστολή Span
API->>DB: Query
DB-->>API: Αποτέλεσμα
API-->>FE: Απάντηση
FE-->>C: Απάντηση
OTEL->>OTEL: Σύνθεση Trace
Κανόνας σχεδιασμού: Τα Traces είναι χρήσιμα μόνο αν οι εφαρμογές μεταδίδουν το Trace Context και παράγουν σχετικά Spans.
10.5 Events ως αφετηρία του Triage
Τα Events είναι χρονικά ταξινομημένες ενδείξεις από τα Kubernetes Components. Συχνά εξηγούν γιατί αποτυγχάνουν το Scheduling, το Image Pull, τα Volumes ή τα Probes.
flowchart TD
problem["Εμφανές πρόβλημα"] --> events["kubectl get events --sort-by=.lastTimestamp"]
events --> scheduling["FailedScheduling"]
events --> image["FailedPull ή BackOff"]
events --> volume["FailedMount ή FailedAttachVolume"]
events --> probe["Unhealthy Probe"]
events --> eviction["Evicted ή NodePressure"]
scheduling --> next1["Έλεγχος πόρων και περιορισμών"]
image --> next2["Έλεγχος Registry και Pull Secret"]
volume --> next3["Έλεγχος PVC, PV και CSI"]
probe --> next4["Έλεγχος υγείας εφαρμογής και Probe"]
eviction --> next5["Έλεγχος πόρων Node"]
Πρακτικός κανόνας: Τα Events δεν αποτελούν μακροχρόνιο Log. Αν χρειάζεσαι μεγαλύτερο ιστορικό, συνέλεξέ τα κεντρικά.
11. Κύκλος ζωής πλατφόρμας, GitOps και Add-ons
11.1 Ροή Bootstrap με kubeadm
Το kubeadm αρχικοποιεί το Control Plane και επιτρέπει την ένταξη επιπλέον Nodes. Δεν παρέχει αυτόματα τις μηχανές, τη δικτυακή υποδομή ή τα Add-ons της πλατφόρμας.
sequenceDiagram
participant A as Admin
participant K as kubeadm
participant CP as Control Plane Node
participant API as API Server
participant W as Worker Node
A->>K: kubeadm init
K->>CP: Δημιουργία Certificates και Configuration
K->>CP: Δημιουργία Static Pods για το Control Plane
CP->>API: Το API Server γίνεται διαθέσιμο
A->>K: Εγκατάσταση CNI
A->>W: kubeadm join με Token
W->>API: Εγγραφή Node
API-->>A: Το Node γίνεται Ready μετά το CNI και το kubelet
Ερώτηση για τον έλεγχο: Γιατί ένα Cluster μπορεί να μην είναι πλήρως λειτουργικό μετά το kubeadm init; Επειδή μπορεί να λείπουν ακόμη το δίκτυο, τα Add-ons, το Storage, το Ingress, οι Policies και το Observability.
11.2 Cluster Upgrade με Node Drain
Ένα ελεγχόμενο Upgrade λαμβάνει υπόψη τα PDBs, τα DaemonSets, τα Stateful Workloads και τις στρατηγικές Rollback.
flowchart TD
plan["Σχεδιασμός Upgrade"] --> backup["Έλεγχος etcd Backup και διαδρομής Restore"]
backup --> cp["Upgrade του Control Plane"]
cp --> node1["Node cordon"]
node1 --> drain["Node drain"]
drain --> upgrade["Upgrade του kubelet και του Runtime"]
upgrade --> uncordon["Node uncordon"]
uncordon --> validate["Έλεγχος Workloads και SLOs"]
validate --> next["Επόμενο Node"]
Κανόνας λειτουργίας: Ένα Upgrade δεν είναι απλώς αλλαγή πακέτων. Είναι προγραμματισμένη διαδικασία της πλατφόρμας, με Validation, χρόνο συνεννόησης και εναλλακτική διαδρομή αν κάτι αποτύχει.
11.3 Ροή GitOps
Το GitOps καθιστά το Git την αυθεντική πηγή για τη δηλωτική ρύθμιση. Ένας Controller συγχρονίζει το Cluster με το Repository.
flowchart LR
dev["Αλλαγή Manifest ή Values"] --> pr["Pull Request"]
pr --> review["Review και έλεγχοι"]
review --> merge["Merge στο Branch προορισμού"]
merge --> repo["Git Repository"]
repo --> gitops["Argo CD ή Flux"]
gitops --> diff["Σύγκριση με το Cluster"]
diff --> sync["Συγχρονισμός"]
sync --> api["Kubernetes API"]
api --> status["Υγεία και Sync Status"]
Πρακτικός κανόνας: Το GitOps δεν αντικαθιστά τις αρχιτεκτονικές αποφάσεις. Επιβάλλει την ιχνηλασιμότητα, τον έλεγχο και τις αναπαραγώγιμες αλλαγές.
11.4 Κύκλος ζωής Helm Release
Το Helm μετατρέπει Templates σε Kubernetes Manifests και διαχειρίζεται Releases. Ένα σφάλμα μπορεί να βρίσκεται στο Chart, στα Values, στο παραγόμενο YAML ή κατά την εφαρμογή του στο Kubernetes.
flowchart TD
chart["Helm Chart"] --> render["helm template"]
values["values.yaml"] --> render
render --> manifests["Παραγόμενα Manifests"]
manifests --> lint["Lint και έλεγχοι Policies"]
lint --> upgrade["helm upgrade --install"]
upgrade --> api["Kubernetes API"]
api --> release["Helm Release Secret"]
api --> resources["Kubernetes Resources"]
Αλυσίδα ελέγχου: Έκδοση Chart → Values → παραγόμενο YAML → Server-Side Validation → κατάσταση Rollout → υγεία εφαρμογής.
11.5 Μοντέλο Overlays στο Kustomize
Το Kustomize τροποποιεί τα βασικά Manifests μέσω Overlays. Αυτό εξυπηρετεί διαφορετικά Environments χωρίς να εισάγει γλώσσα Templating.
flowchart TD
base["base\nDeployment, Service, Config"] --> dev["overlay dev"]
base --> stage["overlay stage"]
base --> prod["overlay prod"]
dev --> patchDev["Patches και Images για dev"]
stage --> patchStage["Patches και Images για stage"]
prod --> patchProd["Patches και Images για prod"]
patchProd --> output["kubectl apply -k overlays/prod"]
Κανόνας σχεδιασμού: Κράτησε το Base σταθερό και τα Overlays μικρά. Μεγάλα ή αντιφατικά Patches δυσκολεύουν τον έλεγχο των Deployments.
11.6 Εξαρτήσεις μεταξύ Add-ons
Τα Cluster Add-ons είναι και τα ίδια Workloads και μπορεί να εξαρτώνται μεταξύ τους. Η βλάβη ενός Add-on συχνά προκαλεί προβλήματα σε Workloads που αρχικά φαίνονται άσχετα.
flowchart TD
cni["CNI"] --> pods["Τα Pods αποκτούν δίκτυο"]
coredns["CoreDNS"] --> discovery["Service Discovery"]
metrics["Metrics Server"] --> hpa["HPA και kubectl top"]
ingress["Ingress ή Gateway Controller"] --> external["Εξωτερική κίνηση"]
csi["CSI"] --> volumes["Persistent Volumes"]
cert["cert-manager"] --> tls["TLS Certificates"]
externaldns["ExternalDNS"] --> dns["DNS Records"]
observability["Monitoring και Logging"] --> ops["Operations και Triage"]
Πρακτικός κανόνας: Τα Platform Add-ons χρειάζονται τον ίδιο κύκλο ζωής με τις εφαρμογές: Versioning, Monitoring, σχέδιο Upgrade και Rollback.
12. Διαγράμματα Troubleshooting
12.1 Γενική ροή Triage για Kubernetes
Ξεκίνα από τη συνολική εικόνα και περιόρισε συστηματικά την αναζήτηση. Μην πηγαίνεις κατευθείαν στα Container Logs αν το Pod δεν εκτελείται ακόμη.
flowchart TD
start["Αναφορά προβλήματος"] --> scope["Ορισμός πεδίου\nNamespace, Workload, χρονική στιγμή"]
scope --> get["kubectl get για σχετικά Resources"]
get --> describe["kubectl describe"]
describe --> events["Ταξινόμηση Events"]
events --> status{Ποιο είναι το Status του Resource?}
status -->|Pending| pending["Scheduling, resources, PVC, Taints"]
status -->|CrashLoop| crash["Logs previous, Exit Code, Probes"]
status -->|Running αλλά μη προσβάσιμο| network["Service, EndpointSlice, DNS, Ingress"]
status -->|Forbidden| rbac["RBAC και ServiceAccount"]
status -->|Πρόβλημα Node| node["Node, kubelet, Runtime, CNI"]
pending --> fix["Διόρθωση και Validation"]
crash --> fix
network --> fix
rbac --> fix
node --> fix
Κανόνας: Τεκμηρίωσε την αιτία, την αλλαγή και το Validation. Η αντιμετώπιση μόνο των συμπτωμάτων δεν αρκεί για αξιόπιστη λειτουργία.
12.2 Pod Pending
Το Pending σημαίνει ότι το Pod δεν εκτελείται ακόμη επιτυχώς σε Node. Η αιτία μπορεί να εμφανίζεται πριν από την ανάθεση σε Node ή κατά τη διάρκειά της.
flowchart TD
pending["Pod Pending"] --> events["Έλεγχος Events"]
events --> scheduling{FailedScheduling?}
scheduling -->|Ναι| resources["CPU, Memory, Pod Quota"]
scheduling -->|Ναι| constraints["Affinity, Taints, Topology"]
scheduling -->|Όχι| image["Δεν ολοκληρώθηκε το Image Pull?"]
events --> volume{Υπάρχουν Volume Events?}
volume -->|Ναι| pvc["PVC, PV, StorageClass, CSI"]
resources --> fix["Διόρθωση Requests ή χωρητικότητας"]
constraints --> fix
pvc --> fix
image --> fix
Αφετηρία ελέγχου: kubectl describe pod <pod> -n <namespace> και kubectl get events -n <namespace> --sort-by=.lastTimestamp.
12.3 CrashLoopBackOff
Το CrashLoopBackOff εμφανίζεται όταν ένα Container ξεκινά επανειλημμένα και τερματίζεται.
flowchart TD
crash["CrashLoopBackOff"] --> previous["kubectl logs --previous"]
previous --> exit["Έλεγχος Exit Code"]
exit --> config["Έλεγχος ConfigMap, Secret και Env"]
exit --> deps["Έλεγχος Dependencies\nDB, API, DNS"]
exit --> probe["Έλεγχος ρυθμίσεων Probe"]
exit --> resources["Έλεγχος OOMKilled ή έλλειψης CPU"]
config --> fix["Deployment της διόρθωσης"]
deps --> fix
probe --> fix
resources --> fix
fix --> rollout["Παρακολούθηση Rollout"]
Anti-pattern: Η διαγραφή του Pod για να σταματήσει προσωρινά το BackOff δεν αντιμετωπίζει τη βασική αιτία.
12.4 ImagePullBackOff
Το ImagePullBackOff δείχνει ότι το kubelet ή το Container Runtime δεν μπορεί να κατεβάσει το Image.
flowchart TD
img["ImagePullBackOff"] --> name["Έλεγχος ονόματος Image και Tag"]
name --> registry["Είναι προσβάσιμο το Registry?"]
registry --> auth["Είναι σωστό το Pull Secret?"]
auth --> tls["Είναι σωστά το TLS και τα Certificates?"]
tls --> arch["Ταιριάζει η αρχιτεκτονική? amd64, arm64"]
arch --> quota["Υπάρχει Rate Limit ή Registry Quota?"]
quota --> fix["Διόρθωση Manifest, Secret ή Registry"]
Εντολή ελέγχου: Το kubectl describe pod εμφανίζει συνήθως το ακριβές μήνυμα σφάλματος του Registry στην ενότητα Events.
12.5 Service χωρίς Endpoints
Ένα Service χωρίς Endpoints συνήθως υποδεικνύει πρόβλημα με Labels, Selectors ή Readiness.
flowchart TD
svc["Το Service δεν απαντά"] --> eps["Έλεγχος EndpointSlices"]
eps --> empty{Δεν υπάρχουν Endpoints?}
empty -->|Ναι| selector["Έλεγχος Service Selector"]
selector --> labels["Έλεγχος Pod Labels"]
labels --> readiness["Έλεγχος Pod Readiness"]
readiness --> ports["Έλεγχος targetPort και containerPort"]
empty -->|Όχι| dataplane["Έλεγχος kube-proxy, eBPF ή NetworkPolicy"]
ports --> fix["Διόρθωση Labels, Readiness ή Ports"]
dataplane --> fix
Αφετηρία ελέγχου: kubectl get svc,endpoints,endpointslices,pods -n <namespace> -o wide.
12.6 Σφάλματα DNS στο Cluster
Τα σφάλματα DNS μπορεί να οφείλονται σε λανθασμένα ονόματα, προβλήματα του CoreDNS, NetworkPolicies ή προβλήματα δικτύου των Nodes.
flowchart TD
dnsfail["Η επίλυση DNS αποτυγχάνει"] --> debugpod["Εκκίνηση Debug Pod στο Namespace"]
debugpod --> fqdn["Δοκιμή σύντομου ονόματος και FQDN"]
fqdn --> coredns["Έλεγχος CoreDNS Pods και Logs"]
coredns --> svc["Έλεγχος kube-dns Service"]
svc --> netpol["Επιτρέπει το NetworkPolicy την κίνηση DNS?"]
netpol --> node["Έλεγχος δικτύου Node και CNI"]
node --> fix["Διόρθωση αιτίας και νέα δοκιμή"]
Ερώτηση για τον έλεγχο: Επηρεάζει το πρόβλημα όλα τα Namespaces ή μόνο ένα; Η απάντηση βοηθά να ξεχωρίσεις ένα πρόβλημα του CoreDNS από ένα πρόβλημα Policy.
12.7 Το Ingress ή Gateway δεν δρομολογεί την κίνηση
Η εξωτερική κίνηση HTTP(S) περνά από πολλά διαδοχικά σημεία. Έλεγξέ τα με τη σειρά.
flowchart TD
fail["Εξωτερικό Request αποτυγχάνει"] --> dns["Είναι σωστό το DNS Record?"]
dns --> lb["Είναι προσβάσιμος ο Load Balancer?"]
lb --> controller["Εκτελείται ο Ingress ή Gateway Controller?"]
controller --> routeClass["Είναι σωστό το IngressClass ή GatewayClass?"]
routeClass --> rule["Είναι σωστά Host, Path, Listener και Route?"]
rule --> svc["Είναι σωστό το Service?"]
svc --> eps["Υπάρχουν EndpointSlices?"]
eps --> pod["Είναι Ready τα Pods και απαντά η εφαρμογή?"]
Κανόνας λειτουργίας: Για κάθε δημόσια υπηρεσία τεκμηρίωσε το όνομα DNS, την πηγή του TLS Certificate, τον Controller, το Routing Object, το Service και την ομάδα που έχει την ευθύνη.
12.8 PVC Pending
Ένα PVC παραμένει σε κατάσταση Pending όταν δεν μπορεί να ολοκληρωθεί το Binding ή το Provisioning, ή όταν το Storage Backend δεν ικανοποιεί τις απαιτήσεις.
flowchart TD
pvc["PVC Pending"] --> sc["Υπάρχει StorageClass?"]
sc --> provisioner["Είναι διαθέσιμος ο Provisioner?"]
provisioner --> quota["Επαρκεί το StorageQuota ή η χωρητικότητα του Backend?"]
quota --> binding["Ταιριάζουν volumeBindingMode και Zone?"]
binding --> access["Είναι κατάλληλο το AccessMode?"]
access --> events["Έλεγχος PVC και CSI Events"]
events --> logs["Έλεγχος Logs του CSI Controller"]
Εντολή ελέγχου: Ξεκίνα με kubectl describe pvc <name> -n <namespace>.
12.9 Node NotReady
Τα προβλήματα ενός Node συχνά επηρεάζουν πολλά Workloads. Έλεγξε το kubelet, το Runtime, το δίκτυο, τον δίσκο, τη μνήμη και τα Certificates.
flowchart TD
node["Node NotReady"] --> cond["Έλεγχος Node Conditions"]
cond --> kubelet["Status και Logs του kubelet"]
cond --> runtime["Είναι προσβάσιμο το Container Runtime?"]
cond --> cni["Είναι Ready το CNI?"]
cond --> pressure["DiskPressure, MemoryPressure, PIDPressure"]
cond --> cert["Certificates και σύνδεση API"]
kubelet --> fix["Διόρθωση Service ή Configuration"]
runtime --> fix
cni --> fix
pressure --> cleanup["Απελευθέρωση πόρων ή αντικατάσταση Node"]
cert --> fix
Κανόνας λειτουργίας: Σε πρόβλημα Node, έλεγξε πάντα αν τα Evictions, τα PDBs και το Rescheduling λειτουργούν όπως αναμένεται.
12.10 Πρόσβαση Forbidden λόγω RBAC
Ένα σφάλμα Forbidden συνήθως δεν είναι πρόβλημα δικτύου. Είναι αποτέλεσμα ελέγχου εξουσιοδότησης.
flowchart TD
forbidden["Το API επιστρέφει Forbidden"] --> identity["Έλεγχος ταυτότητας\nUser, Group, ServiceAccount"]
identity --> verb["Έλεγχος Verb\nget, list, create, patch"]
verb --> resource["Έλεγχος Resource και API Group"]
resource --> scope["Namespace ή ολόκληρο Cluster?"]
scope --> binding["Έλεγχος RoleBinding ή ClusterRoleBinding"]
binding --> cani["Δοκιμή kubectl auth can-i"]
cani --> fix["Παραχώρηση μόνο των απαιτούμενων δικαιωμάτων"]
Anti-pattern: Μη δημιουργείς αυτόματα ClusterRoleBinding προς το cluster-admin. Όρισε τον μικρότερο κατάλληλο κανόνα πρόσβασης.
12.11 OOMKilled
Το OOMKilled σημαίνει ότι ένα Container τερματίστηκε λόγω Memory Limit ή πίεσης μνήμης στο Node.
flowchart TD
oom["OOMKilled"] --> limits["Έλεγχος Memory Limit"]
limits --> usage["Έλεγχος πραγματικής χρήσης Memory"]
usage --> leak["Memory Leak ή απότομη αύξηση φορτίου?"]
usage --> request["Είναι ρεαλιστικό το Request?"]
request --> qos["Έλεγχος κλάσης QoS"]
qos --> node["Έλεγχος Node MemoryPressure"]
leak --> fix["Διόρθωση εφαρμογής ή Limit"]
request --> fix
node --> fix
Πρακτικός κανόνας: Ένα υψηλότερο Memory Limit μπορεί να μειώσει τα συμπτώματα, αλλά δεν διορθώνει Memory Leak ή λανθασμένο σχεδιασμό χωρητικότητας.
12.12 Rollout που έχει κολλήσει
Ένα Rollout συχνά κολλάει επειδή τα νέα Pods δεν είναι Ready ή επειδή τα παλιά Pods δεν μπορούν να απομακρυνθούν.
flowchart TD
rollout["Το Rollout έχει κολλήσει"] --> status["kubectl rollout status"]
status --> rs["Σύγκριση ReplicaSets"]
rs --> newpods["Έλεγχος νέων Pods"]
newpods --> pending["Pending?"]
newpods --> crash["CrashLoop ή αποτυχία Probe?"]
newpods --> readiness["Δεν γίνεται ποτέ Ready?"]
rs --> pdb["Το PDB εμποδίζει το Eviction παλιού Pod?"]
pending --> fix["Διόρθωση Scheduling ή Storage"]
crash --> fix
readiness --> fix
pdb --> fix
Ερώτηση για τον έλεγχο: Βρίσκεται το πρόβλημα στο νέο ReplicaSet, στη δρομολόγηση μέσω Service ή στη στρατηγική Rollout;
12.13 Incident Response σε Kubernetes Cluster
Η αντιμετώπιση ενός Incident απαιτεί τεχνικό περιορισμό της επίδρασης και διατήρηση αποδεικτικών στοιχείων. Μην διαγράφεις βιαστικά ύποπτα Resources αν χρειάζεσαι στοιχεία για Forensics.
stateDiagram-v2
[*] --> Detect
Detect --> Scope: Εντοπισμός επηρεαζόμενων Resources
Scope --> Contain: Απομόνωση δικτύου, δικαιωμάτων ή Node
Contain --> PreserveEvidence: Διατήρηση Logs, Events, Images και Manifests
PreserveEvidence --> RevokeAccess: Rotation Tokens, Secrets και Roles
RevokeAccess --> Remediate: Αφαίρεση βασικής αιτίας
Remediate --> Recover: Ελεγχόμενο Restore ή Rollout
Recover --> Improve: Αυστηρότερες Policies και Monitoring
Improve --> [*]
Κανόνας λειτουργίας: Ετοίμασε τα Runbooks πριν συμβεί ένα Incident. Ο αυτοσχεδιασμός υπό πίεση μπορεί να οδηγήσει σε απώλεια δεδομένων και ελλιπή Root Cause Analysis.
13. Ασκήσεις workshop με διαγράμματα
13.1 Άσκηση: απεικόνισε ένα Deployment
Στόχος είναι να κατανοήσεις τις σχέσεις των Resources στο Cluster και όχι απλώς να τις απομνημονεύσεις.
flowchart LR
task["Rollout ενός Deployment"] --> observe1["kubectl get deploy,rs,pod"]
observe1 --> labels["Έλεγχος Labels και Selector"]
labels --> service["Προσθήκη Service"]
service --> endpoints["Παρακολούθηση EndpointSlices"]
endpoints --> rollout["Αλλαγή Image και παρακολούθηση Rollout"]
rollout --> explain["Συμπλήρωση διαγράμματος με πραγματικά ονόματα"]
Κριτήριο επιτυχίας: Μπορείς να εξηγήσεις ποιο Object δημιουργεί κάποιο άλλο και γιατί ένα Service συνεχίζει να λειτουργεί μετά από Rollout.
13.2 Άσκηση: κάνε ορατή τη συμπεριφορά του NetworkPolicy
Τα NetworkPolicies είναι αφηρημένα. Αυτή η άσκηση δείχνει ποιες διαδρομές κίνησης επιτρέπονται και ποιες αποκλείονται.
flowchart TD
frontend["frontend Pod"] --> api["api Pod"]
api --> db["db Pod"]
debug["Debug Pod"] -. Αποκλείεται .-> db
internet["Internet"] -. Αποκλείεται .-> api
policy1["Policy από frontend προς api"] --> frontend
policy1 --> api
policy2["Policy από api προς db"] --> api
policy2 --> db
Κριτήριο επιτυχίας: Μπορείς να χρησιμοποιήσεις ένα Debug Pod για να δείξεις ποια κίνηση επιτρέπεται και ποια αποκλείεται.
13.3 Άσκηση: ανάλυσε ένα πρόβλημα Storage
Αυτή η άσκηση συνδυάζει τις ενδείξεις από PVC, Events, StorageClass και CSI.
flowchart LR
create["Δημιουργία PVC"] --> pending["Το PVC παραμένει Pending"]
pending --> inspect["describe pvc και Events"]
inspect --> sc["Διόρθωση StorageClass"]
sc --> bind["PVC Bound"]
bind --> pod["Εκκίνηση Pod με Volume Mount"]
pod --> verify["Εγγραφή αρχείου και αναδημιουργία Pod"]
Κριτήριο επιτυχίας: Μπορείς να εξηγήσεις αν το σφάλμα βρίσκεται στο PVC, στο StorageClass, στον Provisioner ή στο Storage Backend.
13.4 Άσκηση: έλεγξε την αλυσίδα ασφαλείας
Αυτή η άσκηση δείχνει ότι η ασφάλεια αποτελείται από πολλούς ελέγχους.
flowchart TD
sa["ServiceAccount με ελάχιστα δικαιώματα"] --> cani["kubectl auth can-i"]
cani --> pod["Pod με SecurityContext"]
pod --> admission["Δοκιμή Pod Security Admission"]
admission --> secret["Έλεγχος πρόσβασης σε Secrets"]
secret --> netpol["Εφαρμογή NetworkPolicy"]
netpol --> audit["Έλεγχος Audit ή Event Traces"]
Κριτήριο επιτυχίας: Μπορείς να εξηγήσεις τους ελέγχους για πρόσβαση στο API, προδιαγραφές Pod, πρόσβαση σε Secrets και δικτυακή κίνηση.
14. Επιλογή διαγραμμάτων ανά θέμα workshop
| Θέμα | Κατάλληλα διαγράμματα | Στόχος |
|---|---|---|
| Εισαγωγή στο Kubernetes | Γενική εικόνα, Control Plane και Worker Nodes, Desired State | Κατανόηση του βασικού μοντέλου |
| Πρώτα Deployments | Deployment, Rollout, Pod Lifecycle, Service και EndpointSlices | Κατανόηση των σχέσεων μεταξύ Resources |
| Δίκτυο | Τύποι Service, DNS, Ingress, Gateway API και NetworkPolicy | Ορατές διαδρομές της κίνησης |
| Storage | PVC, δυναμικό Provisioning, CSI και StatefulSet | Κατανόηση του Persistence και του Binding |
| Ασφάλεια | Κύκλος ζωής API Request, RBAC, Admission, Pod Security και Secrets | Σαφής διάκριση των ελέγχων |
| Operations και Triage | Events, Pending, CrashLoop, Node NotReady και Rollout που έχει κολλήσει | Συστηματικός περιορισμός της αιτίας |
| Σχεδιασμός πλατφόρμας | HA Control Plane, GitOps, Add-ons, Upgrades και Tenant Isolation | Συζήτηση αρχιτεκτονικών αποφάσεων |
| Incident Response | Audit, Runtime Detection και διάγραμμα καταστάσεων Incident Response | Οργάνωση των ενεργειών αντιμετώπισης |
15. Συμβάσεις Mermaid για δικά σου διαγράμματα
15.1 Ονομασία
Χρησιμοποίησε περιγραφικές ετικέτες και σύντομα τεχνικά Identifiers. Τα Node IDs πρέπει να παραμένουν σε ASCII· οι ετικέτες μπορούν να περιέχουν κείμενο φυσικής γλώσσας.
flowchart LR
good["Σαφής ετικέτα\nΤο Service επιλέγει Pods μέσω Labels"] --> better["Ευκολότερη εξήγηση στο workshop"]
bad["svc1"] -. Πολύ ασαφές .-> unclear["Ασαφές νόημα"]
15.2 Μην υπερφορτώνεις τα διαγράμματα
Κάθε διάγραμμα πρέπει να μεταφέρει ένα βασικό μήνυμα. Αν χρειάζεσαι περισσότερα από τρία επίπεδα πληροφορίας, χώρισε το περιεχόμενο σε περισσότερα διαγράμματα.
flowchart TD
topic["Ένα θέμα"] --> diag1["Διάγραμμα 1\nΑρχιτεκτονική"]
topic --> diag2["Διάγραμμα 2\nΡοή"]
topic --> diag3["Διάγραμμα 3\nTroubleshooting"]
15.3 Προσαρμογή του τεχνικού βάθους στο κοινό
Για αρχάριους δείξε τις βασικές σχέσεις. Για προχωρημένους πρόσθεσε Events, Status, Controllers και περιορισμούς.
flowchart LR
beginner["Βασικό επίπεδο"] --> simple["Pods, Services, Deployments"]
intermediate["Μεσαίο επίπεδο"] --> flow["Rollouts, Probes, Storage, δίκτυο"]
professional["Προχωρημένο επίπεδο"] --> ops["HA, Upgrades, Add-ons, Observability"]
security["Ασφάλεια"] --> controls["RBAC, Admission, Policies, Incident Response"]
16. Πηγές και τεχνικός προσανατολισμός
Αυτή η συλλογή διαγραμμάτων βασίζεται στην επίσημη τεκμηρίωση του Kubernetes. Χρησιμοποίησε τους παρακάτω συνδέσμους για τεχνική επαλήθευση όταν εμβαθύνεις στα διαγράμματα στο workshop ή τα προσαρμόζεις σε συγκεκριμένη πλατφόρμα.
- Kubernetes Components
- Cluster Architecture
- Nodes
- Communication between Nodes and the Control Plane
- Services
- EndpointSlices
- Ingress
- Gateway API
- Network Policies
- Persistent Volumes
- Storage Classes
- Dynamic Volume Provisioning
- RBAC
- RBAC Good Practices
- Pod Security Standards
- Pod Security Admission
- Admission Controllers
- Operating etcd clusters for Kubernetes
- Creating Highly Available Clusters with kubeadm