Kubernetes Workshop: Intermediate – Ασκήσεις με λύσεις
Αναφορά: Workshop Intermediate
Επίπεδο δυσκολίας: Intermediate
Μορφή: πρακτικό Lab με ενδεικτικές λύσεις και οδηγίες βήμα προς βήμα
Στόχος αυτού του εγγράφου ασκήσεων
Αυτό το έγγραφο συμπληρώνει το Workshop Intermediate με πρακτικές εργασίες, λύσεις και οδηγίες βήμα προς βήμα. Εστιάζει στην επιλογή Workloads, σε Init Containers, Sidecars, Ephemeral Containers, Probes, Graceful Shutdown, PodDisruptionBudgets, Requests, Limits, QoS, LimitRange, ResourceQuota, Scheduling, NetworkPolicy, DNS, Ingress ή Gateway API, Storage, Helm, Kustomize και συστηματικό Troubleshooting.
Προαπαιτούμενα
Χρειάζεστε:
- Lab Cluster με λειτουργικό CNI,
- CoreDNS,
kubectl,- προαιρετικά
helm, - προαιρετικά
kustomizeήkubectl kustomize, - προαιρετικά StorageClass,
- προαιρετικά Ingress Controller ή Gateway Controller.
Προτεινόμενο Namespace:
export NS=workshop-intermediate
kubectl create namespace "$NS"
kubectl config set-context --current --namespace="$NS"
Επισκόπηση ασκήσεων
| Αρ. | Θέμα | Αποτέλεσμα |
|---|---|---|
| 1 | Επιλογή Workload | Τεχνική διάκριση Deployment, Job και CronJob. |
| 2 | Init Container και Sidecar | Παρακολούθηση του κύκλου ζωής των Containers στο Pod. |
| 3 | Probes και κύκλος ζωής | Σαφής διάκριση Startup, Readiness και Liveness. |
| 4 | Resources, QoS, LimitRange, Quota | Έλεγχος ορίων Namespace και επίδρασης στο Scheduling. |
| 5 | Scheduling | Δοκιμή Node Labels, nodeSelector, Taints και Tolerations. |
| 6 | NetworkPolicy και DNS | Δημιουργία Default Deny με στοχευμένες εξαιρέσεις. |
| 7 | Ingress ή Gateway | Εξωτερική έκθεση HTTP App ή σωστή ταξινόμηση των περιορισμών. |
| 8 | PVC και StatefulSet | Δοκιμή Persistent State. |
| 9 | Helm και Kustomize | Σύγκριση παραγόμενων Manifests. |
| 10 | Διαδρομή Troubleshooting | Συστηματική διόρθωση συνήθων σφαλμάτων. |
Μέρος A – Ασκήσεις
Άσκηση 1: Επιλογή Workload Resource
Στόχος
Αποφασίστε αν τεχνικά ταιριάζει Deployment, Job ή CronJob.
Σενάριο
Πρέπει να μοντελοποιήσετε τρεις απαιτήσεις:
- Ένας Web Server πρέπει να εκτελείται συνεχώς και να ενημερώνεται με Rolling Updates.
- Ένα Data Migration πρέπει να εκτελείται μία φορά και έπειτα να ολοκληρώνεται.
- Μια εργασία Cleanup πρέπει να εκτελείται κάθε ώρα.
Εργασία
- Δημιουργήστε ελάχιστο Manifest για κάθε περίπτωση.
- Εφαρμόστε τα Manifests.
- Ελέγξτε το Status και τα Events.
- Τεκμηριώστε γιατί ταιριάζει το επιλεγμένο Resource.
Άσκηση 2: Ταξινόμηση Init Container και Sidecar
Στόχος
Κατανοήστε πότε πρέπει να εκτελεστεί ένα Init Container πριν από την εφαρμογή και πότε ένα πρόσθετο Container μοιράζεται τον κύκλο ζωής του ίδιου Pod.
Εργασία
Δημιουργήστε Pod στο οποίο:
- ένα Init Container γράφει αρχείο σε
emptyDir, - το App Container διαβάζει αυτό το αρχείο,
- ένα Sidecar Container γράφει περιοδικά ένα Heartbeat File.
Ελέγξτε:
- τη σειρά εκκίνησης των Containers,
- τα Logs όλων των Containers,
- τα περιεχόμενα του κοινόχρηστου Volume.
Άσκηση 3: Σωστός διαχωρισμός Probes
Στόχος
Διορθώστε ελαττωματικό Probe Configuration που προκαλεί επανεκκινήσεις.
Σενάριο
Μια δοκιμαστική εφαρμογή εκκινεί αργά. Το Liveness Probe ελέγχει την ίδια διαδρομή με το Readiness υπερβολικά νωρίς.
Εργασία
- Δημιουργήστε Deployment με σκόπιμα υπερβολικά επιθετικό Liveness Probe.
- Παρατηρήστε Events και επανεκκινήσεις.
- Προσθέστε Startup Probe.
- Διαχωρίστε εννοιολογικά Readiness και Liveness.
- Εξηγήστε γιατί το Readiness ελέγχει την κυκλοφορία, ενώ το Liveness προκαλεί επανεκκινήσεις.
Άσκηση 4: Resources, QoS, LimitRange και ResourceQuota
Στόχος
Ορίστε Requests και Limits, παρατηρήστε τις QoS Classes και δημιουργήστε όρια Namespace.
Εργασία
- Δημιουργήστε LimitRange με προεπιλεγμένα Requests και Limits.
- Δημιουργήστε ResourceQuota για CPU, Memory και αριθμό Pods.
- Κάντε Rollout τριών Pods:
- χωρίς ρητά Resources,
- με Requests μικρότερα από τα Limits,
- με Requests ίσα με τα Limits.
- Προσδιορίστε τις QoS Classes.
- Προκαλέστε σκόπιμα υπέρβαση Quota.
Άσκηση 5: Scheduling με Node Labels, nodeSelector, Taint και Toleration
Στόχος
Ελέγξτε την τοποθέτηση Pods και ερμηνεύστε Events για την κατάσταση Pending.
Εργασία
- Προσθέστε σε Lab Node το Label
workshop-role=apps. - Δημιουργήστε Pod με αντίστοιχο
nodeSelector. - Δημιουργήστε Pod με
nodeSelectorπου δεν ταιριάζει. - Ορίστε Taint στο Node.
- Δημιουργήστε ένα Pod χωρίς Toleration και ένα με Toleration.
- Τεκμηριώστε τα Events.
Άσκηση 6: NetworkPolicy Default Deny με εξαίρεση DNS
Στόχος
Δημιουργήστε Policy Default Deny και έπειτα επιτρέψτε ρητά την επικοινωνία DNS και της εφαρμογής.
Εργασία
- Δημιουργήστε δύο Deployments:
frontendκαιbackend. - Δημιουργήστε Services και για τα δύο.
- Ελέγξτε ότι το
frontendμπορεί να συνδεθεί στοbackend. - Δημιουργήστε Policy Default Deny για Ingress και Egress.
- Ελέγξτε ότι η κυκλοφορία αποκλείεται.
- Επιτρέψτε DNS Egress.
- Επιτρέψτε σύνδεση του
frontendπρος τοbackendστην Port 8080. - Ελέγξτε ξανά.
Άσκηση 7: Παροχή Ingress ή Gateway
Στόχος
Εκθέστε μια HTTP Application μέσω Ingress ή, εναλλακτικά, περιγράψτε τα Resources του Gateway API αν δεν είναι εγκατεστημένος Controller.
Εργασία
- Ελέγξτε αν υπάρχει Ingress Controller ή Gateway Controller.
- Αναπτύξτε HTTP App.
- Δημιουργήστε είτε Ingress Resource είτε παράδειγμα Gateway/HTTPRoute.
- Ελέγξτε Controller Events, Backend Service και Routing.
- Τεκμηριώστε γιατί ένα Ingress Resource δεν έχει αποτέλεσμα χωρίς Controller.
Άσκηση 8: Χρήση PVC και StatefulSet
Στόχος
Εκτελέστε μικρό Stateful Workload με PVC και ελέγξτε αν τα δεδομένα διατηρούνται μετά την αναδημιουργία του Pod.
Εργασία
- Ελέγξτε τα υπάρχοντα StorageClasses.
- Δημιουργήστε StatefulSet με
volumeClaimTemplates. - Γράψτε ένα αρχείο στο Volume.
- Διαγράψτε το Pod.
- Μετά την αναδημιουργία του, ελέγξτε αν το αρχείο εξακολουθεί να υπάρχει.
- Τεκμηριώστε γιατί ένα Lab με
hostPathδεν αποτελεί παραδοχή για Production.
Άσκηση 9: Σύγκριση Helm και Kustomize
Στόχος
Κάντε Render των Manifests πριν τα εφαρμόσετε και συγκρίνετε Helm με Kustomize.
Εργασία
- Δημιουργήστε ένα μικρό Kustomize Base και ένα
devOverlay. - Κάντε Render του Overlay.
- Δημιουργήστε ένα ελάχιστο Helm Chart ή χρησιμοποιήστε ένα τοπικό παράδειγμα Chart.
- Κάντε Render του Helm Chart.
- Συγκρίνετε τη δυνατότητα Review, την Παραμετροποίηση και τον κίνδυνο σφαλμάτων.
Άσκηση 10: Διαδρομή Troubleshooting
Στόχος
Διερευνήστε μεθοδικά πέντε συνήθη μοτίβα σφαλμάτων.
Μοτίβα σφαλμάτων
- Pod παραμένει
Pendingλόγω λανθασμένουnodeSelector. - Pod εμφανίζει
ImagePullBackOffλόγω λάθος Image Tag. - Pod εμφανίζει
CrashLoopBackOffλόγω ελαττωματικού Startup Command. - PVC παραμένει
Pendingλόγω λάθος StorageClass. - Service δεν έχει Endpoints λόγω λανθασμένου Selector.
Εργασία
Για κάθε σφάλμα τεκμηριώστε:
- το σύμπτωμα,
- την εντολή διάγνωσης,
- τα σχετικά Events ή Logs,
- την αιτία,
- τη διόρθωση,
- την επαλήθευση.
Μέρος B – Λύσεις και οδηγίες βήμα προς βήμα
Λύση 1: Επιλογή Workload Resource
Deployment για Web Server που εκτελείται συνεχώς
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: workshop-intermediate
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
Job για Migration μίας εκτέλεσης
apiVersion: batch/v1
kind: Job
metadata:
name: migration
namespace: workshop-intermediate
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: migration
image: busybox:1.36
command: ["sh", "-c", "echo Migration running; sleep 3; echo Migration complete"]
CronJob για Cleanup κάθε ώρα
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup
namespace: workshop-intermediate
spec:
schedule: "0 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup
image: busybox:1.36
command: ["sh", "-c", "date; echo cleanup"]
Έλεγχος:
kubectl apply -f deployment.yml
kubectl apply -f job.yml
kubectl apply -f cronjob.yml
kubectl get deployment,job,cronjob,pod
kubectl logs job/migration
Τεχνική απόφαση:
| Απαίτηση | Resource | Αιτία |
|---|---|---|
| HTTP Service που εκτελείται συνεχώς | Deployment | Replicas, Rollouts και Rollbacks. |
| Migration μίας εκτέλεσης | Job | Η ολοκληρωμένη κατάσταση είναι ο τεχνικός στόχος. |
| Cleanup κάθε ώρα | CronJob | Δημιουργία Jobs βάσει χρονοδιαγράμματος. |
Λύση 2: Init Container και Sidecar
Manifest:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
namespace: workshop-intermediate
labels:
app: lifecycle-demo
spec:
volumes:
- name: shared
emptyDir: {}
initContainers:
- name: init-write
image: busybox:1.36
command: ["sh", "-c", "echo prepared > /shared/init.txt"]
volumeMounts:
- name: shared
mountPath: /shared
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do cat /shared/init.txt; sleep 30; done"]
volumeMounts:
- name: shared
mountPath: /shared
- name: sidecar
image: busybox:1.36
command: ["sh", "-c", "while true; do date > /shared/heartbeat.txt; sleep 10; done"]
volumeMounts:
- name: shared
mountPath: /shared
Έλεγχος:
kubectl apply -f lifecycle-demo.yml
kubectl get pod lifecycle-demo
kubectl describe pod lifecycle-demo
kubectl logs lifecycle-demo -c init-write
kubectl logs lifecycle-demo -c app
kubectl exec lifecycle-demo -c app -- ls -l /shared
kubectl exec lifecycle-demo -c app -- cat /shared/heartbeat.txt
Εξήγηση:
- Τα Init Containers εκτελούνται πριν από τα App Containers και πρέπει να ολοκληρωθούν επιτυχώς.
- Τα Sidecars εκτελούνται παράλληλα με την εφαρμογή.
- Το
emptyDirμοιράζει αρχεία μέσα στο ίδιο Pod, αλλά δεν διατηρεί τα δεδομένα μετά τη διαγραφή του Pod.
Λύση 3: Σωστά Probes
Ανθεκτικό δοκιμαστικό Manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: probe-demo
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: probe-demo
template:
metadata:
labels:
app: probe-demo
spec:
containers:
- name: app
image: registry.k8s.io/e2e-test-images/agnhost:2.53
args: ["netexec", "--http-port=8080"]
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 2
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
Έλεγχος:
kubectl apply -f probe-demo.yml
kubectl rollout status deployment/probe-demo
kubectl describe pod -l app=probe-demo
kubectl get pods -w
Ενδεικτική εξήγηση:
- Το Startup Probe προστατεύει τις αργές εκκινήσεις· όσο δεν επιτυγχάνει, τα Liveness και Readiness δεν είναι ενεργά.
- Το Readiness καθορίζει αν ένα Pod περιλαμβάνεται στα Endpoints των Services.
- Το Liveness καθορίζει αν το kubelet επανεκκινεί το Container.
- Ένα υπερβολικά επιθετικό Liveness Probe δημιουργεί βρόχους επανεκκίνησης.
Λύση 4: Resources, QoS, LimitRange και ResourceQuota
LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
namespace: workshop-intermediate
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 256Mi
max:
cpu: "1"
memory: 512Mi
ResourceQuota:
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
namespace: workshop-intermediate
spec:
hard:
pods: "5"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "3"
limits.memory: 2Gi
Έλεγχος:
kubectl apply -f limitrange.yml
kubectl apply -f quota.yml
kubectl describe limitrange defaults
kubectl describe resourcequota namespace-quota
Pod με Burstable QoS:
apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
Pod με Guaranteed QoS:
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
Έλεγχος QoS:
kubectl apply -f burstable-pod.yml
kubectl apply -f guaranteed-pod.yml
kubectl get pod burstable-pod -o jsonpath='{.status.qosClass}{"\n"}'
kubectl get pod guaranteed-pod -o jsonpath='{.status.qosClass}{"\n"}'
Προκαλέστε υπέρβαση Quota:
apiVersion: v1
kind: Pod
metadata:
name: too-large
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: "2"
memory: 2Gi
limits:
cpu: "2"
memory: 2Gi
Αναμενόμενο αποτέλεσμα:
kubectl apply -f too-large.yml
Ο API Server απορρίπτει το Resource λόγω του ResourceQuota.
Λύση 5: Scheduling
Επιλέξτε Node:
NODE=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
kubectl label node "$NODE" workshop-role=apps
kubectl get nodes --show-labels | grep workshop-role
Pod με nodeSelector που ταιριάζει:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-ok
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: apps
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Pod με nodeSelector που δεν ταιριάζει:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-pending
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: does-not-exist
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Έλεγχος:
kubectl apply -f scheduled-ok.yml
kubectl apply -f scheduled-pending.yml
kubectl get pods -o wide
kubectl describe pod scheduled-pending
Ορίστε Taint:
kubectl taint node "$NODE" dedicated=apps:NoSchedule
Pod με Toleration:
apiVersion: v1
kind: Pod
metadata:
name: tolerated
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: apps
tolerations:
- key: dedicated
operator: Equal
value: apps
effect: NoSchedule
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Cleanup:
kubectl delete pod scheduled-ok scheduled-pending tolerated --ignore-not-found
kubectl taint node "$NODE" dedicated=apps:NoSchedule-
kubectl label node "$NODE" workshop-role-
Εξήγηση:
- Το
nodeSelectorείναι υποχρεωτική συνθήκη: χωρίς Node που να ταιριάζει, το Pod μένειPending. - Ένα Taint αποκλείει Pods.
- Ένα Toleration επιτρέπει σε Pod να ανεχθεί Taint· από μόνο του δεν επιβάλλει την τοποθέτηση.
Λύση 6: NetworkPolicy και DNS
Δοκιμαστική εφαρμογή:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: registry.k8s.io/e2e-test-images/agnhost:2.53
args: ["netexec", "--http-port=8080"]
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: workshop-intermediate
spec:
selector:
app: backend
ports:
- name: http
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: curlimages/curl:8.8.0
command: ["sh", "-c", "sleep 3600"]
Δοκιμή πριν από την Policy:
kubectl apply -f net-demo.yml
kubectl wait --for=condition=Available deployment/backend --timeout=90s
kubectl wait --for=condition=Available deployment/frontend --timeout=90s
FRONTEND=$(kubectl get pod -l app=frontend -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$FRONTEND" -- curl -s http://backend:8080/hostname
Default Deny:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: workshop-intermediate
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Επιτρέψτε DNS Egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: workshop-intermediate
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Επιτρέψτε επικοινωνία Frontend προς Backend:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: workshop-intermediate
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-egress-to-backend
namespace: workshop-intermediate
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
Έλεγχος:
kubectl apply -f default-deny.yml
kubectl apply -f allow-dns-egress.yml
kubectl apply -f allow-frontend-backend.yml
kubectl exec "$FRONTEND" -- nslookup backend
kubectl exec "$FRONTEND" -- curl -s --max-time 5 http://backend:8080/hostname
Σημείωση:
Τα NetworkPolicies λειτουργούν μόνο αν το CNI Plugin τα επιβάλλει.
Λύση 7: Ingress ή Gateway
Ελέγξτε αν υπάρχει Controller:
kubectl get ingressclass
kubectl get gatewayclass 2>/dev/null || true
kubectl get pods -A | grep -Ei 'ingress|gateway|traefik|nginx|envoy|haproxy'
Παράδειγμα Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
namespace: workshop-intermediate
spec:
rules:
- host: web.localtest.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
Έλεγχος:
kubectl apply -f ingress.yml
kubectl describe ingress web
kubectl get ingress web
Παράδειγμα Gateway API, αν είναι εγκατεστημένο:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
namespace: workshop-intermediate
spec:
parentRefs:
- name: shared-gateway
namespace: gateway-system
hostnames:
- web.localtest.me
rules:
- backendRefs:
- name: backend
port: 8080
Τεχνική εξήγηση:
- Το Ingress περιγράφει μόνο κανόνες.
- Ένας Ingress Controller πρέπει να μετατρέψει τον κανόνα σε Proxy ή Load Balancer Configuration.
- Το Gateway API διαχωρίζει σαφέστερα την ευθύνη υποδομής από το Application Routing.
Λύση 8: PVC και StatefulSet
Ελέγξτε το StorageClass:
kubectl get storageclass
StatefulSet:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-demo
namespace: workshop-intermediate
spec:
serviceName: data-demo
replicas: 1
selector:
matchLabels:
app: data-demo
template:
metadata:
labels:
app: data-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do sleep 3600; done"]
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
Εφαρμογή και δοκιμή:
kubectl apply -f statefulset.yml
kubectl rollout status statefulset/data-demo
kubectl exec data-demo-0 -- sh -c 'echo persistence-test > /data/test.txt'
kubectl delete pod data-demo-0
kubectl wait --for=condition=Ready pod/data-demo-0 --timeout=120s
kubectl exec data-demo-0 -- cat /data/test.txt
Αναμενόμενη κατάσταση:
Το αρχείο εξακολουθεί να υπάρχει μετά την αναδημιουργία του Pod, επειδή το PVC προσαρτάται ξανά στο data-demo-0.
Ταξινόμηση:
- Τα StatefulSets παρέχουν σταθερά Pod Names και σταθερή αντιστοίχιση PVC.
- Ένα τοπικό Volume
hostPathείναι βολικό σε Lab, αλλά δεν είναι φορητό ούτε αποτελεί Storage για Production.
Λύση 9: Helm και Kustomize
Δομή Kustomize:
kustomize-demo/
base/
deployment.yml
service.yml
kustomization.yml
overlays/
dev/
kustomization.yml
base/kustomization.yml:
resources:
- deployment.yml
- service.yml
overlays/dev/kustomization.yml:
resources:
- ../../base
namePrefix: dev-
labels:
- pairs:
environment: dev
images:
- name: nginx
newTag: "1.27"
Render:
kubectl kustomize kustomize-demo/overlays/dev
kubectl apply -k kustomize-demo/overlays/dev --dry-run=server
Ελάχιστο Helm Chart:
helm create webchart
helm template web ./webchart
helm lint ./webchart
Σύγκριση:
| Κριτήριο | Helm | Kustomize |
|---|---|---|
| Μοντέλο | Package με Templates και Values. | Base/Overlay χωρίς Template Language. |
| Πλεονέκτημα | Πολλές παράμετροι, Releases και οικοσύστημα Charts. | Κοντά στο YAML, εύκολο Review. |
| Κίνδυνος | Πολύπλοκα Templates μπορεί να είναι δύσκολο να επαληθευτούν. | Τα Overlays μπορεί να γίνουν δυσνόητα. |
| Υποχρεωτικός έλεγχος | helm template, helm lint. |
kubectl kustomize, dry-run. |
Λύση 10: Διαδρομή Troubleshooting
Ενδεικτική διάγνωση:
| Μοτίβο σφάλματος | Διάγνωση | Αιτία | Διόρθωση |
|---|---|---|---|
Pending |
kubectl describe pod |
Κανένα Node δεν ταιριάζει με το nodeSelector. |
Διορθώστε το Label ή αφαιρέστε τον Selector. |
ImagePullBackOff |
Events του Pod | Λάθος Image, Tag ή Registry. | Ορίστε έγκυρο Image. |
CrashLoopBackOff |
kubectl logs --previous |
Η διεργασία τερματίζεται με σφάλμα. | Διορθώστε Startup Command ή Configuration της εφαρμογής. |
PVC Pending |
kubectl describe pvc |
Λείπει StorageClass ή Provisioner. | Διορθώστε ή διαθέστε StorageClass. |
| Service χωρίς Endpoints | kubectl get endpoints, έλεγχος Labels |
Ο Selector δεν ταιριάζει. | Διορθώστε τον Selector ή τα Pod Labels. |
Τυπική ακολουθία:
kubectl get all
kubectl get pod -o wide
kubectl describe pod <pod>
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl logs <pod>
kubectl logs <pod> --previous
kubectl get svc,endpoints,endpointslices
kubectl describe pvc <pvc>
Cleanup
kubectl delete namespace workshop-intermediate
Λίστα ελέγχου αξιολόγησης
| Κριτήριο | Ολοκληρώθηκε; |
|---|---|
| Τα Workload Resources διακρίθηκαν τεχνικά. | ☐ |
| Εξηγήθηκαν Init Container, Sidecar και App Container. | ☐ |
| Τα Probes διαχωρίστηκαν σωστά. | ☐ |
| Εφαρμόστηκαν Requests, Limits, QoS, LimitRange και Quota. | ☐ |
| Ερμηνεύτηκαν τα Scheduling Events. | ☐ |
| Εξετάστηκε NetworkPolicy που λαμβάνει υπόψη το DNS. | ☐ |
| Εξηγήθηκε ο ρόλος του Ingress/Gateway Controller. | ☐ |
| Δοκιμάστηκαν PVC και StatefulSet. | ☐ |
| Έγινε Render με Helm και Kustomize. | ☐ |
| Τεκμηριώθηκε η διαδρομή Troubleshooting. | ☐ |