Τι είναι το Kubernetes (και γιατί να σε νοιάζει)
Το θεμέλιο: containers, orchestration και γιατί όλη η βιομηχανία «παίζει» σε αυτό.
Ας ξεκινήσουμε με τα βασικά. Μια εφαρμογή container (Docker) πακετάρει τον κώδικά σου μαζί με ό,τι χρειάζεται για να τρέξει: runtime, βιβλιοθήκες, ρυθμίσεις. Το αποτέλεσμα είναι «κουτιά» που τρέχουν όμοια παντού — στο laptop σου, σε ένα Raspberry Pi ή στο cloud. Δεν υπάρχει πια το κλασικό «αλλά σε μένα δούλευε!».
Όταν όμως έχεις πολλά containers — δεκάδες ή εκατοντάδες — εμφανίζονται σοβαρές ερωτήσεις: ποιος τα ξεκινά ξανά όταν κρασάρουν; πώς μοιράζεται η κίνηση μεταξύ τους; πώς κάνεις deploy νέα έκδοση χωρίς downtime; πώς κρύβεις τα secrets; Εδώ μπαίνει το Kubernetes (K8s): ένας orchestrator που διαχειρίζεται containers σε κλίμακα, σε οποιονδήποτε συνδυασμό μηχανών.
Φαντάσου το Kubernetes ως τον αρχισεφ μιας μεγάλης κουζίνας: εσύ του λες «θέλω 5 πιάτα μακαρονάδας» (desired state) και εκείνος φροντίζει να έχει 5 μάγειρες να τα φτιάχνουν, αντικαθιστά όποιον λιποθυμάει, μοιράζει τις παραγγελίες και κρατάει το ψυγείο γεμάτο. Εσύ απλά περιγράφεις τι θέλεις — όχι πώς θα γίνει.
Pod = η μικρότερη μονάδα εκτέλεσης (1+ containers που μοιράζονται IP). Node = μία μηχανή (φυσική ή VM) που τρέχει pods. Control plane = ο «εγκέφαλος» που αποφασίζει. Deployment = περιγραφή «θέλω Ν αντίγραφα αυτού». Service = σταθερή «διεύθυνση» για pods που αλλάζουν IP συνέχεια. Ingress = η «πόρτα» από το δίκτυό σου προς τα pods.
Και γιατί να το τρέξω στο σπίτι;
Γιατί το homelab είναι από τους καλύτερους τρόπους να μάθεις πραγματικά Kubernetes — χωρίς cloud λογαριασμούς που τρέχουν «κατά λάθος» με 300€/μήνα. Στο σπίτι κάνεις τα λάθη σου δωρεάν: σπάς πράγματα, τα ξαναφτιάχνεις, και σε λίγους μήνες έχεις δεξιότητες που ζητούνται σχεδόν παντού: DevOps, SRE, backend, data engineering.
Ταυτόχρονα, ένα cluster στο σπίτι είναι και πρακτικό: τρέχει τα self-hosted apps σου (password manager, Nextcloud, Home Assistant, Pi-hole) με rolling updates, TLS, monitoring και auto-restart — σαν μικρογραφία ενός πραγματικού datacenter. Και ναι: το στυλ «κάνω restart το router και όλα ξανασηκώνονται μόνα τους» είναι από τις πιο ικανοποιητικές εμπειρίες του hobby.
K3s: το Kubernetes που τρέχει και σε Raspberry Pi
Γιατί K3s και όχι «πλήρες» K8s — και τι κερδίζεις ή χάνεις πραγματικά.
Το πρόβλημα του «κανονικού» Kubernetes για οικιακή χρήση: χρειάζεται αρκετή RAM, ξεχωριστό etcd, ingress controller, CNI plugin, storage provisioner… Πρακτικά 5–6 πράγματα να εγκαταστήσεις και να συντονίσεις πριν γράψεις το πρώτο σου pod. Το K3s, φτιαγμένο από την Rancher Labs (σήμερα SUSE), λύνει ακριβώς αυτό.
Συνοπτικά: είναι ένα single binary ~70MB που με μία εντολή σου δίνει πλήρες, πιστοποιημένο Kubernetes — ίδιο API, ίδια kubectl, ίδια manifests. Τα «βαρικά» εξαρτήματα έχουν αντικατασταθεί από ελαφριές εκδόσεις και ό,τι χρειάζεσαι έρχεται bundled.
| Χαρακτηριστικό | Κλασικό Kubernetes | K3s |
|---|---|---|
| Εγκατάσταση | Πολλά components, kubeadm | 1 binary, 1 εντολή |
| Ελάχ. RAM | ~2GB+ ανά node (πρακτικά 4GB) | ~512MB |
| Datastore | etcd cluster | SQLite ενσωματωμένο (ή etcd/pgsql για HA) |
| Ingress | Το εγκαθιστάς μόνος | Traefik bundled |
| LoadBalancer | Metallb ή cloud LB | ServiceLB bundled |
| Storage | Χρειάζεσαι provisioner | local-path-provisioner |
| Runtime / CNI | containerd + Calico/Cilium… | containerd + Flannel bundled |
| Πιστοποίηση CNCF | ✔ | ✔ πλήρως conformant |
| Ιδανικό για | Datacenter / cloud | Homelab, edge, IoT, ARM |
Το K3s είναι certified Kubernetes distribution. Ό,τι μαθαίνεις εδώ — kubectl, YAML, Deployments, Ingress — μεταφέρεται ακριβώς και σε EKS/AKS/GKE. Δεν μαθαίνεις «κάτι αντίστοιχο», μαθαίνεις το ίδιο πράγμα.
Το τίμημα; Κάποια bundled components είναι απλούστερα από τις «μεγάλες» εναλλακτικές (π.χ. το Flannel δεν κάνει NetworkPolicies από μόνο του). Όλα όμως αντικαθίστανται αργότερα — και στο homelab αυτό σπάνια χρειάζεται.
Το homelab σου: επιλογή hardware
Δεν χρειάζεσαι server rack. Χρειάζεσαι κάτι φθηνό, αθόρυβο και οικονομικό σε ρεύμα.
Ο χρυσός κανόνας για αρχή: ξεκίνα με ένα (1) δυνατό node και μεγάλωσε αργότερα. Με το K3s, το server node μπορεί να τρέχει και workloads — ένα cluster ενός node είναι πλήρως λειτουργικό. Προσθέτεις agents όποτε θες, με μηδενική ανακατασκευή.
| Επιλογή | Κόστος | RAM | Ρεύμα | Αξιολόγηση |
|---|---|---|---|---|
| Mini PC x64 (Intel N100: Beelink, GMKtec) | ~150–200€ | 8–16GB | 6–15W | ★★★★★ Η καλύτερη επιλογή — NVMe, αθόρυβο, γρήγορο |
| Μεταχειρισμένο SFF (Dell OptiPlex, Lenovo ThinkCentre) | ~100–180€ | 16–32GB | 15–40W | ★★★★☆ Τεράστια αναβαθμισιμότητα, λίγο πιο θορυβώδες |
| Raspberry Pi 5 (8GB) | ~120€ | 8GB | 5–10W | ★★★☆☆ Ωραίο για cluster 3×Pi, αλλά ARM images + αποθήκευση = περιπλοκές |
| Παλιό laptop | 0€ | 8–16GB | 5–20W | ★★★☆☆ Δωρεάν + builtin «UPS» η μπαταρία, αλλά θόρυβος/ήδη παλιό |
| Μεταχειρισμένος rack server (R720, DL380) | ~200€+ | 64GB+ | 100–200W | ★☆☆☆☆ Αθόρυβο σαν τρακτέρ, λογαριασμός ρεύματος διπλασιάζεται |
Ένα mini PC με Intel N100, 16GB RAM, 512GB NVMe (~180€). Τρέχει άνετα K3s, 15–20 pods, Prometheus, Grafana, Argo CD. Αργότερα προσθέτεις 2 Raspberry Pi ως agents (~80€) για να δεις replicas να μετακινούνται μεταξύ nodes — η «κανονική» cluster εμπειρία.
Λεπτομέρειες που μετράνε
- Αποθήκευση: σε Raspberry Pi απόφυγε SD cards — χαλάουν σε μήνες υπό φόρτο. Πάρε USB-SSD. Σε x64, ένα NVMe 512GB είναι ιδανικό.
- Δίκτυο: ενσύρματο ethernet, πάντα. WiFi σε cluster node είναι συνταγή για ακατανόητα timeouts. Κράτα σταθερή IP (DHCP reservation στον router είναι το πιο απλό).
- Ρεύμα: 15W 24/7 ≈ ~11 kWh/μήνα ≈ 2–4€/μήνα. Ο λογαριασμός δεν θα σε πτοήσει.
- Θερμοκρασία: καλή αερισμένη θέση, όχι σε κλειστό συρτάρι. Τα mini PCs σχεδιάζονται για 24/7 λειτουργία, αλλά ο θόρυβος των ανεμιστήρων ανεβαίνει με τη θερμότητα.
Αρχιτεκτονική: πώς μοιάζει ένα K3s cluster
Μία εικόνα που αξίζει 1000 λέξεις — τι τρέχει σε κάθε node.
- Server node: εκτελεί το control plane (apiserver, scheduler, controllers) και τη βάση SQLite. Δέχεται τις εντολές σου από το kubectl στο port
6443. - Agent nodes: δεν «σκέφτονται» — λαμβάνουν οδηγίες, τρέχουν pods και αναφέρουν πίσω. Αν πέσει ένας agent, το control plane επαναλαμβάνει τα pods του σε άλλους.
- kubelet + containerd: σε κάθε node: ο τοπικός «μαître» που κατεβάζει images και σηκώνει containers.
- Flannel/VXLAN: δημιουργεί ένα εικονικό δίκτυο, ώστε τα pods σε διαφορετικά nodes να «βλέπονται» σαν να είναι στο ίδιο LAN (port
8472/udp).
Για μάθηση: 1 node αρκεί. Για «πραγματική» εμπειρία (failover, μετακινήσεις): 1 server + 2 agents. Για HA του control plane (production pattern): 3 server nodes με embedded etcd — καλύτερα αργότερα, όχι στην πρώτη εβδομάδα.
Προετοιμάζουμε το Ubuntu Server
Το «θεμέλιο» του node σου: OS, σταθερή IP, SSH. 15 λεπτά δουλειάς.
Προτείνω Ubuntu Server 24.04 LTS (ή Debian 12 — εξίσου άριστο). Χωρίς desktop environment: 512MB RAM λιγότερα, λιγότερες ενημερώσεις, λιγότερα unexpected popups. Κατέβασε το ISO και φτιάξε USB με το Balena Etcher ή Rufus (σε Raspberry Pi: Raspberry Pi Imager, επιλέγοντας «Ubuntu Server 24.04»).
Κατά την εγκατάσταση: δημιούργησε user (π.χ. lab), enable SSH, και όρισε να κάνει install τα openssh/openvpn δωρεάν extras. Μετά το reboot, συνδέσου από τον υπολογιστή σου:
ssh [email protected]
# Πρώτα πράγματα μετά την πρώτη σύνδεση
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl jq htop git
# Όρισε ξεκάθαρο hostname — θα το βλέπεις παντού
sudo hostnamectl set-hostname k3s-server
Σταθερή IP με netplan
Το cluster σου πρέπει να «ξέρει» πού ζει το server. Αν το router σου κάνει DHCP reservation, τέλειο — τέλος. Διαφορετικά, βάλε στατική IP στο Ubuntu:
network:
ethernets:
eth0:
addresses: [192.168.1.100/24]
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [1.1.1.1, 9.9.9.9]
version: 2
sudo netplan apply
ip a show eth0 # επιβεβαίωσε την IP
# SSH keys — να μη γράφεις κωδικό συνέχεια
ssh-keygen -t ed25519
ssh-copy-id [email protected]
Το kubelet δεν θέλει swap. Το Ubuntu Server το έχει off by default, αλλά έλεγξέ το — αν υπάρχει:
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
free -h # swap πρέπει να δείχνει 0B
Εγκατάσταση K3s server — η φημισμένη μία εντολή
60 δευτερόλεπτα. Πραγματικά. Αυτό είναι το σημείο που θα χαμογελάσεις.
Στο server node, σαν απλός χρήστης με sudo:
curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644
# └── installer └─ flags: kubeconfig με mode 644
# (η 644 είναι ok για homelab· σε shared υπολογιστή κράτα το default 600)
Τι μόλις έγινε; Κατέβηκε το binary k3s (μέσα σε λίγα δευτερόλεπτα), δημιουργήθηκε systemd service k3s.service, ξεκίνησε το control plane με SQLite datastore, και «φύτευτηκαν» αυτόματα: Traefik, CoreDNS, ServiceLB, local-path storage. Χωρίς κανένα extra βήμα.
sudo kubectl get nodes
NAME STATUS ROLES VERSION
k3s-server Ready control-plane v1.30.4+k3s
kubectl get pods -A
NAMESPACE NAME READY STATUS
kube-system coredns-77ccd...4xq2z 1/1 Running
kube-system traefik-65bdc...k9m2f 1/1 Running
kube-system local-path-provisioner 1/1 Running
Βλέπεις Ready; Έχεις Kubernetes. Τόσο απλά. Το kubeconfig ζει στο /etc/rancher/k3s/k3s.yaml — για να δουλεύει το kubectl χωρίς sudo:
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER ~/.kube/config
export KUBECONFIG=~/.kube/config # βάλ' το και στο ~/.bashrc
Σημαντικό: το node token
Θα το χρειαστείς για να «καλέσεις» agents στο cluster (κράτα το μυστικό — είναι ο admin κλειδί)
sudo cat /var/lib/rancher/k3s/server/node-token
# K10...HASH...::server:LONG-STRING-HERE ← copy αυτό
--tls-san=192.168.1.100 (αν θες kubectl από άλλο PC), --disable=traefik (αν προτιμάς ingress-nginx), --node-ip=192.168.1.100. Σύνταξη: curl -sfL https://get.k3s.io | sh -s - --tls-san=192.168.1.100. Πλήρης λίστα: k3s server --help.
Προσθέτουμε agents — το cluster μεγαλώνει
Δεύτερο/τρίτο Raspberry Pi ή PC; Εντάξου: μία εντολή.
Σε κάθε επιπλέον μηχανή (πρόσεξε: πρέπει να «βλέπει» το server στο δίκτυο και να έχει την ίδια αρχιτεκτονική ή συμβατά images):
curl -sfL https://get.k3s.io | \
K3S_URL=https://192.168.1.100:6443 \
K3S_TOKEN=K10xxxx... \
sh -
Πίσω στο server, σε λίγα δευτερόλεπτα:
kubectl get nodes
NAME STATUS ROLES VERSION
k3s-server Ready control-plane v1.30.4+k3s
k3s-agent-1 Ready <none> v1.30.4+k3s
k3s-agent-2 Ready <none> v1.30.4+k3s
Αν έχεις ufw/firewalld ενεργό, δώσε στα agents πρόσβαση στο server: 6443/tcp (API), 8472/udp (Flannel VXLAN), 10250/tcp (kubelet). Αν κάποιος agent κολλάει στο NotReady, το 90% των φορών φταίει δίκτυο/firewall.
kubectl: τα πρώτα σου παιχνίδια
Τα 8 commands που θα πληκτρολογείς 100 φορές την εβδομάδα.
Το kubectl είναι το «τηλεκοντρόλ» του cluster. Δουλεύει με pattern kubectl <ρήμα> <αντικείμενο>. Δοκίμασε τα παρακάω με τη σειρά — δεν σπάς τίποτα:
kubectl get nodes -o wide # nodes + IPs + versions
kubectl get pods -A # όλα τα pods, όλα τα namespaces
kubectl get pods -A -w # live παρακολούθηση (Ctrl+C για έξοδο)
kubectl get ns # namespaces
kubectl top nodes # CPU/RAM ανά node (με metrics-server)
kubectl describe pod <name> # το «ιατρικό φάκελο» ενός pod
kubectl logs -f <pod> # logs του pod, -f = follow
kubectl api-resources | head # τι είδους objects υπάρχουν
Είναι «φακέλοι» που οργανώνουν resources. Π.χ. kube-system = τα system pods, monitoring = Prometheus/Grafana, media = Jellyfin. Το flag -n <ns> στοχεύει συγκεκριμένο namespace· το -A σημαίνει «όλους».
Το πρώτο σου deployment (YAML 101)
Το κείμενο που θα γράφεις χιλιάδες φορές: 3 αντικείμενα σε ένα αρχείο.
Στο Kubernetes όλα είναι YAML: περιγράφεις την επιθυμητή κατάσταση και το cluster την πραγματοποιεί — και τη διατηρεί για πάντα. Φτιάξε τον φάκελο σου και το πρώτο σου αρχείο:
apiVersion: v1
kind: ConfigMap
metadata:
name: web-html
data:
index.html: |
<h1>Γεια σου από το δικό μου Kubernetes! 🚀</h1>
<p>Αυτό το pod τρέχει σε {{NODE_NAME}} με IP {{POD_IP}}</p>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web
labels: {app: my-web}
spec:
replicas: 2
selector: {matchLabels: {app: my-web}}
template:
metadata: {labels: {app: my-web}}
spec:
containers:
- name: web
image: nginx:1.27-alpine
ports: [{containerPort: 80}]
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap: {name: web-html}
---
apiVersion: v1
kind: Service
metadata:
name: my-web-svc
spec:
type: ClusterIP
selector: {app: my-web}
ports: [{port: 80, targetPort: 80}]
Δες τι περιέχει: ένα ConfigMap (το static HTML), ένα Deployment (2 replicas nginx που κάνουν mount το HTML) κι ένα Service (η «διεύθυνση» που σταθερά δείχνει στα 2 pods, όσο κι αν αυτά αναδημιουργούνται). Το --- χωρίζει αντικείμενα στο ίδιο αρχείο.
kubectl apply -f my-first-app.yaml
configmap/web-html created
deployment.apps/my-web created
service/my-web-svc created
kubectl get pods -l app=my-web
NAME READY STATUS RESTARTS
my-web-7f8b9c6d5-abcde 1/1 Running 0
my-web-7f8b9c6d5-fghij 1/1 Running 0
# Δοκιμή από το εσωτερικό του cluster
kubectl run tmp --rm -it --image=curlimages/curl -- \
curl -s http://my-web-svc
Γεια σου από το δικό μου Kubernetes! 🚀
Μαγικά πειράματα (κάνε τα!)
# 1) Scale σε 5 replicas — σε 2 δευτερόλεπτα
kubectl scale deployment my-web --replicas=5
# 2) Σκότωσε ένα pod — δες το να ξανασηκώνεται μόνο του
kubectl delete pod my-web-7f8b9c6d5-abcde
kubectl get pods -w
# 3) Rolling update σε νέα έκδοση image, μηδέν downtime
kubectl set image deployment/my-web web=nginx:1.28-alpine
kubectl rollout status deployment/my-web
# 4) Αν κάτι πήγε στραβά: γύρνα πίσω
kubectl rollout undo deployment/my-web
Το #2 είναι η ουσία του Kubernetes: σκότωσες» ένα pod και δεν έγινε τίποτα — ένα άλλο εμφανίστηκε στη θέση του αυτόματα, και το Service συνέχισε να δείχνει σωστά. Αυτή η αυτό-ίαση (self-healing) είναι όλο το «μάγκικο» — και την έχεις ήδη δουλέψει.
Ingress: πραγματικά ονόματα και TLS
Από το http://192.168.1.100:31234 στο https://myweb.homelab.local — με κλειδαριά.
Μέχρι τώρα «χτυπούσες» τις εφαρμογές σου με IP και πόρτα. Ο Ingress αλλάζει το παιχνίδι: ένας κανόνας λέει στον Traefik (που ήδη τρέχει από το K3s) «ό,τι φτάνει με hostname myweb.homelab.local → πήγαινέ το στο service my-web-svc». Δεκάδες εφαρμογές, όλες στις πόρτες 80/443, με καθαρά ονόματα — μία μόνο «πόρτα» προς τα έξω.
Βήμα 1 — DNS: δώσε ονόματα στις εφαρμογές
- Σε 10 δευτερόλεπτα: πρόσθεσε στο
/etc/hostsτου PC σου (Windows:C:\Windows\System32\drivers\etc\hosts) τη γραμμή192.168.1.100 myweb.homelab.local— δουλεύει μόνο για εκείνη τη συσκευή. - Για όλο το σπίτι: με Pi-hole ή AdGuard Home φτιάχνεις DNS record
*.homelab.local → 192.168.1.100. Κάθε συσκευή, κάθε app, αυτόματα. - Για αληθινό TLS από το internet: πάρε δωρεάν domain στο duckdns.org (π.χ.
mylab.duckdns.org) — μόνο με δημόσιο domain βγάζεις πιστοποιητικά Let's Encrypt.
Βήμα 2 — το πρώτο σου Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-web
spec:
ingressClassName: traefik
rules:
- host: myweb.homelab.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-web-svc
port: {number: 80}
kubectl apply -f my-web-ingress.yaml
# Άνοιξε στον browser: http://myweb.homelab.local ✔
Βήμα 3 — TLS με cert-manager + Let's Encrypt
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
kubectl -n cert-manager get pods # περίμενε να δεις 3/3 Running
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef: {name: letsencrypt-key}
solvers:
- http01:
ingress: {ingressClassName: traefik}
Τέλος, στο Ingress πρόσθεσε annotation και ενότητα tls (και άλλαξε το host στο δημόσιο domain σου):
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts: [myweb.mylab.duckdns.org]
secretName: my-web-tls
Ο έλεγχος http01 απαιτεί ο Let's Encrypt να «χτυπήσει» το http://mylab.duckdns.org/.well-known/acme-challenge/… — δηλαδή ο router σου πρέπει να κάνει port-forward της 80 (και της 443) στο 192.168.1.100. Αν δεν θες καθόλου port-forward, χρησιμοποίησε DNS-01 με DuckDNS token: φτιάξε solver dns01: {providers: [{duckdns: {token: ...}}]} και βγάλε wildcard certificate *.mylab.duckdns.org για όλες τις εφαρμογές με ένα πιστοποιητικό.
Δώσε kubectl apply ξανά και σε 30–60 δευτερόλεπτα ο cert-manager έχει βγάλει πιστοποιητικό — δωρεάν, αυτόματο, ανανεούμενο για πάντα. Το lockaki στον browser σου από hardcoded IP:port γίνεται πράγμα.
Storage: όταν τα δεδομένα θέλουν να μείνουν
Pods έρχονται και φεύγουν. Τα αρχεία σου όχι — αν τα ζητήσεις σωστά.
Προεπιλογή στο Kubernetes: ό,τι γράψει ένα container στο filesystem του χάνεται όταν το pod ξαναδημιουργηθεί. Λογικό για stateless apps, καταστροφικό για βάσεις δεδομένων. Η λύση: PersistentVolumeClaim (PVC) — «ζητάω 2GB αποθήκευσης» — και το K3s, χάρη στον bundled local-path-provisioner, την ικανοποιεί αμέσως φτιάχνοντας φάκελο στο δίσκο του node.
Το δοκιμάζουμε
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes: [ReadWriteOnce]
storageClassName: local-path
resources:
requests: {storage: 2Gi}
# μέσα στο spec.template.spec:
containers:
- name: app
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim: {claimName: data-pvc}
kubectl apply -f data-pvc.yaml
kubectl get pvc
NAME STATUS VOLUME CAPACITY STORAGECLASS
data-pvc Bound pvc-x 2Gi local-path
# Γράψε ένα αρχείο μέσα
kubectl exec deploy/my-web -- sh -c 'echo "ζω!" > /data/test.txt'
# Σκότωσε το pod — και δες το αρχείο να επιβιώνει
kubectl delete pod -l app=my-web
kubectl exec deploy/my-web -- cat /data/test.txt
ζω!
Ο όγκος «δένεται» με τον συγκεκριμένο node που τον δημιούργησε. Αν το pod μετακινηθεί σε άλλο node (multi-node cluster), δεν θα βρει τα δεδομένα του. Για πραγματική πολυ-νομική αποθήκευση με replication και snapshots, το επόμενο βήμα είναι το Longhorn (ένα Helm install — άφησέ το για όταν νιώσεις άνετα με τα βασικά).
Monitoring: Prometheus + Grafana σε 5 λεπτά
Γράφητα CPU/RAM, alerts, και το «γιατί είναι αργό το Pi μου;» — με απαντήσεις.
Καλή είδηση πρώτα: το K3s φέρνει bundled το metrics-server, οπότε το kubectl top nodes και kubectl top pods δουλεύουν ήδη. Για πλήρη εικόνα (ιστορικά, γραφήματα, dashboards) το standard είναι ο συνδυασμός Prometheus + Grafana — και εγκαθίστανται με Helm, τον package manager του Kubernetes, σε μία εντολή.
# 1) Helm — αν δεν το έχεις ήδη
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 2) Το "kube-prometheus-stack": Prometheus + Grafana + Alertmanager
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace \
--set grafana.adminPassword='admin123' \
--set grafana.persistence.size=2Gi
kubectl -n monitoring port-forward svc/monitoring-grafana 3000:80
# Browser: http://localhost:3000 — user: admin / admin123
Μέσα θα βρεις έτοιμα dashboards (π.χ. Kubernetes / Compute Resources / Nodes) που δείχνουν τα πάντα: CPU, RAM, δίσκο, πόσα pods τρέχουν, ακόμα και πότε το node «πνίγηκε». Δοκίμασε να αφήσεις ένα kubectl top pods -A δίπλα σε ένα Grafana dashboard — ξαφνικά το cluster σου παύει να είναι μαύρο κουτί.
Το kube-prometheus-stack θέλει άνετα ~1GB RAM συνολικά. Σε mini PC 16GB: μηδέν πρόβλημα. Σε Pi 4GB με πολλά apps: προτίμησε το ελαφρύ PathFinder/uptime scripts ή άφησέ το Monitoring να μπει αργότερα — το cluster δεν «κρυώνει» χωρίς αυτό.
GitOps με Argo CD: το Git γίνεται το αφεντικό
Σταματάς να «τρέχεις» deployments με το χέρι — τα βγάζεις από ένα repository.
Η ιδέα του GitOps είναι απλή αλλά αλλάζει τα πάντα: όλα τα YAML σου ζουν σε ένα Git repository (π.χ. GitHub, Gitea στο σπίτι σου). Μία εφαρμογή — εδώ το Argo CD — παρακολουθεί το repo και κάνει το cluster να «ταιριάζει» με ό,τι γράφεις εκεί. Κάνεις git push, το deploy γίνεται μόνο του. Σβήνεις ένα YAML, η εφαρμογή φεύγει. Ολόκληρο ιστορικό αλλαγών, undo = git revert.
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl -n argocd get pods # περίμενε Running
# Πρόσβαση στο UI
kubectl -n argocd port-forward svc/argocd-server 8080:443
# Browser: https://localhost:8080
# Ο αρχικός κωδικός admin
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d; echo
Στο UI (user: admin + τον κωδικό που βγήκε) κάνεις New App, δίνεις το repo σου (π.χ. https://github.com/<user>/homelab), path ., destination default namespace, και επιλέγεις Auto-Sync. Από εδώ και πέρα: κάθε git push που αλλάζει τα YAML σου εμφανίζεται στο cluster μέσα σε δευτερόλεπτα, και το Argo CD δείχνει με χρώματα τι ταιριάζει και τι όχι.
Ανέβασε τα my-first-app.yaml και my-web-ingress.yaml σε ένα private GitHub repo και συνάρτησέ τα με το Argo CD. Από εκεί και πέρα, το homelab σου έχει «source of truth» — και το rebuild σε νέα μηχανή γίνεται: install K3s + Argo CD + «sync». Πέντε λεπτά, ολόκληρο σύστημα.
Backups: γιατί «θα το κοιτάξω αύριο» είναι λάθος
Τρία επίπεδα προστασίας, από το απλό στο επαγγελματικό.
Σε ένα cluster, τα «τιμημένα» σου είναι δύο: τα manifests (πώς είναι φτιαγμένο το σύστημα) και τα δεδομένα (PVCs, βάσεις). Οι τακτικές:
- Επίπεδο 1 — Git: όλα τα manifests σε repo (κάνεις το GitOps της προηγούμενης ενότητας και το έχεις ήδη). Με GitOps, ο κόπος rebuild ενός cluster είναι 15 λεπτά.
- Επίπεδο 2 — Snapshot της κατάστασης: το K3s κρατά την κατάσταση του cluster στο
/var/lib/rancher/k3s/server/db— ένα νυχτερινό backup αυτού του φακέλου (και τουstorage/για τα PVC) σε εξωτερικό δίσκο/NAS σε καλύπτει πλήρως. - Επίπεδο 3 — Velero / Longhorn: εργαλεία για backup όλου του cluster + volumes (σε S3/MinIO, με snapshots). Φέρνοντάς τα όταν το homelab γίνει «σοβαρό» infrastructure.
#!/bin/bash
# Νυχτερινό backup σε NAS/εξωτερικό δίσκο (mount ως /mnt/backup)
BACKUP=/mnt/backup
sudo tar czf $BACKUP/k3s-$(date +%F).tgz \
/var/lib/rancher/k3s/server/db \
/var/lib/rancher/k3s/storage
# Κράτα 14 μέρες — σβήνε τα παλιά
find $BACKUP -name 'k3s-*.tgz' -mtime +14 -delete
chmod +x backup-k3s.sh
crontab -e
# πρόσθεσε τη γραμμή (κάθε βράδυ 03:00):
# 0 3 * * * /home/lab/backup-k3s.sh
Backup που δεν έχεις δοκιμάσει να επαναφέρεις δεν είναι backup — είναι ελπίδα. Μία φορά τον μήνα: σβήσε επίτηδες κάτι (π.χ. ένα ConfigMap), κάνε restore, επιβεβαίωσε. Αν θες να παίξεις «από το μηδέν» σε νέα μηχανή: fresh K3s + kubectl apply από το Git σου — καλύτερο test από όλα.
Troubleshooting: τα 6 λάθη που WILL κάνεις
Καμία παγίδα δεν σε περιμένει — μαθαίνεις να τις αναγνωρίζεις σε 5 δευτερόλεπτα.
| Σύμπτωμα | Τι συνήθως σημαίνει | Η εντολή-κλειδί |
|---|---|---|
ImagePullBackOff | Λάθος όνομα image, χωρίς internet, ή x64 image σε ARM node | kubectl describe pod |
CrashLoopBackOff | Η εφαρμογή μέσα κρασάρει (missing env, λάθος config) | kubectl logs --previous |
Pending | Δεν χωράει στον node, ή PVC που δεν γίνεται Bound | kubectl describe pod ( Events) |
| Node NotReady | K3s service κάτω, ή μπλοκαρισμένα ports firewall (8472/udp) | journalctl -u k3s -f στον node |
| Ingress → 404 | Λάθος service name/port στο ingress, ή λάθος host στο DNS | kubectl get ingress |
kubectl → connection refused | Λάθος IP στο kubeconfig, ή σβηστό k3s server | sudo systemctl status k3s |
Η γενική μέθοδος πάντα ίδια: kubectl get pods -A → βρες τον «άρρωστο» → kubectl describe (διάβασε τα Events στο τέλος — εκεί γράφεται σχεδόν πάντα η απάντηση) → kubectl logs. Και μην ξεχνάς τα logs του ίδιου του K3s: journalctl -u k3s -f --lines=50.
Το k9s είναι ένα terminal UI για kubectl — βλέπεις pods/services/logs σε πραγματικό χρόνο, χωρίς να γράφεις εντολές. Εγκατάσταση ενός binary, ανοίγεις και γράφεις : + όνομα resource. Από τα εργαλεία που μόλις το δοκιμάσεις, δεν γυρνάς πίσω.
Cheat Sheet: οι εντολές της καθημερινότητας
Αποθήκευσε αυτή την ενότητα — θα την ανοίγεις συνέχεια.
🖥️ Nodes
📦 Pods
🔬 Debug
🚀 Rollouts
💾 Storage & Secrets
🧹 Καθάρισμα
Επόμενα βήματα: το homelab μεγαλώνει
Έχεις ζωντανό cluster, ingress, TLS, monitoring και GitOps. Πού πας από εδώ;
- Self-hosted apps: πέρνα πραγματικά apps — Vaultwarden (passwords), Pi-hole/AdGuard (DNS για όλο το σπίτι), Home Assistant, Nextcloud, Jellyfin. Κάθε ένα = ένα YAML + ένα ingress.
- Longhorn: κατανεμημένο storage με replication — τα PVC σου επιβιώνουν και σε πτώση node.
- MetallB: αν θες «πραγματικές» LoadBalancer IPs στο LAN σου αντί για port-forwards.
- Flux CD: η εναλλακτική του Argo CD — πιο «engineer-y», με Kustomize/Helm native.
- Renovate / pinning: αυτόματες PRs όταν βγαίνουν νέες εκδόσεις images — giữει τα apps σου φρέσκα.
- 3ος node + HA: τρία server nodes με embedded etcd — το control plane επιβιώνει και από πτώση μηχανής.
- Πειραματίσου ανεμελιά: το ωραίο του homelab είναι ότι τίποτα δεν είναι production. Σπάσε το, ξαναφτιάξ' το, μάθε.
1) Ανέβασε το repo σου στο GitHub και συνάρτησε το Argo CD. 2) Βγάλε wildcard TLS για το *.homelab.local ή DuckDNS σου. 3) Φτιάξε ένα dashboard (Grafana ή Homepage) που δείχνει όλα τα apps σου. Μετά από αυτά, δεν είσαι πια «αρχάριος» — είσαι homelabber με προσωπικό cluster. 🎉
Συχνές ερωτήσεις
Οι απαντήσεις που ψάχνουν όλοι πριν στήσουν K3s.
Τι hardware χρειάζομαι για K3s homelab;
Ένα Raspberry Pi αρκεί για αρχή. Για σοβαρό cluster, x86 mini PC ή παλιό laptop με 8GB+ RAM.
K3s ή κανονικό Kubernetes;
K3s: ελαφρύ single-binary Kubernetes, ιδανικό για homelab και edge. Το κανονικό Kubernetes θέλει περισσότερους πόρους και συντήρηση.
Πώς παίρνω backup στο K3s;
Velero για cluster resources, snapshots για volumes (Longhorn), και GitOps repo ως source of truth για όλα τα manifests.
Πώς βρίσκω τι φταίει όταν πέφτει pod;
kubectl logs/describe για άμεση εικόνα, Prometheus/Grafana για τάσεις και alerts.