Ενότητα 9 · 9.1
Κατανόηση των containers
Ενότητα 9: Docker και docker compose · Χρόνος ανάγνωσης: 10 λεπτά
Στόχος μαθήματος: Μετά από αυτό το μάθημα μπορείτε να εξηγήσετε τι είναι ένα container, πώς διαφέρει από μια εικονική μηχανή, πού μένουν τα δεδομένα ενός container και πότε το Docker έχει νόημα στον server σας.
Βασικές έννοιες: image, container, layer (επίπεδο), registry (Docker Hub), tag, digest, namespaces, cgroups, κοινός kernel, εφήμερο σύστημα αρχείων, volume, bind mount, δημοσίευση θύρας, επίσημο image
Γιατί containers;
Ας υποθέσουμε ότι θέλετε να εκτελείτε στο VPS σας μια σελίδα κατάστασης που δείχνει αν ο ιστότοπός σας λειτουργεί. Το πρόγραμμα είναι γραμμένο σε Node.js, χρειάζεται μια συγκεκριμένη έκδοσή του και επιπλέον περίπου διακόσιες βιβλιοθήκες. Χωρίς containers τα εγκαθιστάτε όλα αυτά στον server σας, δίπλα στον web server και τη βάση δεδομένων σας. Έναν χρόνο αργότερα θέλετε ένα δεύτερο πρόγραμμα που χρειάζεται άλλη έκδοση του Node.js. Τότε αρχίζει ο γρίφος.
Ένα container λύνει αυτό το πρόβλημα. Ο δημιουργός του προγράμματος παραδίδει το πρόγραμμα μαζί με όλα όσα χρειάζεται, σε ένα ενιαίο πακέτο: ένα image. Στον server σας εκκινείτε αυτό το image ως container. Το πρόγραμμα βλέπει τα δικά του αρχεία, το δικό του Node.js, τις δικές του βιβλιοθήκες και δεν συγκρούεται με τον υπόλοιπο server σας. Δεν το χρειάζεστε πια; Διαγράφετε το container και το image, και δεν μένει τίποτα πίσω στο /usr ή στο /etc.
Το Docker είναι το πιο γνωστό εργαλείο για τη λήψη images και την εκτέλεση containers. Υπάρχουν εναλλακτικές (Podman, το ίδιο το containerd), αλλά οι έννοιες είναι παντού ίδιες.
Image, container και registry
Τρεις λέξεις που θα συναντάτε συνεχώς:
- Image: ένα πρότυπο μόνο για ανάγνωση με σύστημα αρχείων (πρόγραμμα, βιβλιοθήκες, ρυθμίσεις) και την εντολή που πρέπει να εκκινήσει. Ένα image αποτελείται από επίπεδα (layers): ένα βασικό επίπεδο (για παράδειγμα ένα γυμνό Debian), από πάνω ένα επίπεδο με Node.js και από πάνω το πρόγραμμα. Δύο images με το ίδιο βασικό επίπεδο μοιράζονται αυτό το επίπεδο στον δίσκο σας.
- Container: ένα αντίγραφο ενός image που εκτελείται (ή έχει σταματήσει). Πάνω από τα επίπεδα μόνο για ανάγνωση, το container αποκτά ένα δικό του λεπτό επίπεδο εγγραφής. Από ένα image μπορείτε να εκκινήσετε δέκα containers.
- Registry: το σημείο όπου βρίσκονται τα images, όπως το Docker Hub (
docker.io) ή το registry του GitHub (ghcr.io). Το Docker κατεβάζει ένα image μεdocker pull.
Το όνομα ενός image μοιάζει έτσι:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestΤο τμήμα μετά την άνω και κάτω τελεία είναι το tag: μια ετικέτα για μια έκδοση. Ένα tag μπορεί να αλλάξει: το caddy:2 δείχνει σήμερα σε άλλο build από ό,τι σε τρεις μήνες, μόλις κυκλοφορήσει μια νέα 2.x. Αν θέλετε να καθορίσετε με ακρίβεια ποιο image εκτελείτε, χρησιμοποιήστε το digest: ένα αποτύπωμα του περιεχομένου, όπως caddy@sha256:.... Αυτό δεν αλλάζει ποτέ. Το tag latest είναι απλώς ένα όνομα που επιλέγει ο δημιουργός· δεν σημαίνει αυτόματα "η νεότερη σταθερή έκδοση" και γι' αυτό είναι κακή επιλογή αν θέλετε να ξέρετε τι εκτελείται.
Δεν είναι εικονική μηχανή
Ένα container μοιάζει με μια μικρή εικονική μηχανή, αλλά δεν είναι. Αυτή η διαφορά είναι σημαντική για την ασφάλεια.
| Εικονική μηχανή (όπως το VPS σας) | Container | |
|---|---|---|
| Kernel | Δικός της kernel | Μοιράζεται τον kernel του host |
| Εκκίνηση | Από δευτερόλεπτα έως λεπτά, ένα ολόκληρο λειτουργικό σύστημα | Συνήθως σε ένα δευτερόλεπτο, μόνο το πρόγραμμα |
| Διαχωρισμός | Από τον hypervisor, σε επίπεδο υλικού | Από τον kernel: namespaces και cgroups |
| Μέγεθος | Gigabytes | Συχνά από δεκάδες έως εκατοντάδες megabytes |
Ένα container είναι στην ουσία μια συνηθισμένη διεργασία στον server σας, την οποία ο kernel τοποθετεί σε απομονωμένο περιβάλλον:
- τα namespaces φροντίζουν ώστε η διεργασία να έχει τη δική της εικόνα για αρχεία, διεργασίες, δίκτυο και χρήστες. Μέσα στο container το πρόγραμμα φαίνεται να είναι η διεργασία με αριθμό 1 και δεν βλέπει τον υπόλοιπο server σας·
- τα cgroups περιορίζουν πόσο επεξεργαστή και μνήμη μπορεί να χρησιμοποιήσει.
Επειδή όλα τα containers μοιράζονται τον ίδιο kernel, ο διαχωρισμός είναι λιγότερο αυστηρός από ό,τι μεταξύ δύο VPS. Ένα κενό ασφαλείας στον kernel ή ένα container που λαμβάνει υπερβολικά δικαιώματα μπορεί να επηρεάσει τον host. Γι' αυτό ισχύουν οι κανόνες αυτής της ενότητας: εκτελείτε μόνο images που εμπιστεύεστε, μη δίνετε σε containers περισσότερα δικαιώματα από όσα χρειάζονται και μην κάνετε ποτέ mount το /var/run/docker.sock ή το / σε ένα container (μάθημα 9.3 και 10.2).
Πού μένουν τα δεδομένα σας;
Αυτή είναι η κλασική παγίδα για αρχάριους. Το επίπεδο εγγραφής ενός container είναι εφήμερο: αν διαγράψετε το container (για παράδειγμα σε μια ενημέρωση, μάθημα 9.4), χάνεται ό,τι έγραψε εκεί το πρόγραμμα. Τα δεδομένα που πρέπει να διατηρηθούν ανήκουν επομένως έξω από το container:
- Volume: ένας χώρος αποθήκευσης που διαχειρίζεται το ίδιο το Docker (κάτω από το
/var/lib/docker/volumes/). Του δίνετε ένα όνομα, για παράδειγμαuptime-kuma, και το συνδέετε με έναν φάκελο μέσα στο container:-v uptime-kuma:/app/data. - Bind mount: ένας συνηθισμένος φάκελος στον server σας που προσαρτάτε στο container:
-v /srv/vaultwarden:/data. Πρακτικό, επειδή βλέπετε τα αρχεία απευθείας και τα συμπεριλαμβάνετε εύκολα στα αντίγραφα ασφαλείας σας (ενότητα 8).
Ένα container με σωστά volumes μπορείτε να το πετάξετε και να το δημιουργήσετε ξανά χωρίς να χάσετε τίποτα. Ακριβώς έτσι λειτουργεί η ενημέρωση: λήψη νέου image, διαγραφή του παλιού container, νέο container στα ίδια volumes. Γι' αυτό συμπεριλάβετε τα volumes στο σχέδιο αντιγράφων ασφαλείας σας (μάθημα 8.1).
Δημοσίευση θυρών
Ένα container έχει το δικό του δίκτυο. Ένα web πρόγραμμα που ακούει μέσα στο container στη θύρα 3001 δεν είναι προσβάσιμο από έξω από τον server, μέχρι να δημοσιεύσετε αυτή τη θύρα: -p 3001:3001 (θύρα host:θύρα container). Προσοχή: χωρίς διεύθυνση, το Docker δημοσιεύει τη θύρα σε όλες τις διευθύνσεις του server σας, δηλαδή 0.0.0.0 και [::]. Αυτό σημαίνει: προσβάσιμη από όλο το internet, και το Docker το ρυθμίζει παρακάμπτοντας το ufw (μάθημα 9.3). Η ασφαλής συνήθεια είναι η δημοσίευση στο loopback, -p 127.0.0.1:3001:3001, με ένα reverse proxy με https μπροστά (μάθημα 9.4).
Ποιος φτιάχνει το image;
Ένα image είναι λογισμικό κάποιου άλλου που μπορεί να εκτελείται ως root στον server σας. Γι' αυτό ελέγξτε ποιος είναι ο δημιουργός:
- τα Docker Official Images (όπως
caddy,nginx,postgres) συντηρούνται από το Docker μαζί με τους δημιουργούς· - images από τον ίδιο τον δημιουργό (όπως
louislam/uptime-kumaκαιvaultwarden/server), αναγνωρίσιμα από το όνομα που αναφέρει ο ιστότοπος του έργου· - images από αγνώστους με ονόματα που μοιάζουν: μην τα χρησιμοποιείτε.
Χρησιμοποιείτε πάντα το όνομα που αναφέρεται στον επίσημο ιστότοπο του έργου, όχι το πρώτο που εμφανίζει μια αναζήτηση.
Πότε ναι, πότε όχι;
Το Docker είναι πρακτικό για προγράμματα που ο δημιουργός παρέχει ως image, για υπηρεσίες που θέλετε να μπορείτε να διαγράψετε ή να μετακινήσετε γρήγορα και για την εκτέλεση πολλών προγραμμάτων με διαφορετικές απαιτήσεις το ένα δίπλα στο άλλο. Για τη βάση του server σας (SSH, firewall, ενημερώσεις) δεν χρησιμοποιείτε containers. Και ένας μεμονωμένος ιστότοπος με nginx και PHP από την πηγή πακέτων (μάθημα 7.2) λειτουργεί άψογα χωρίς Docker. Ένα container προσθέτει ένα επίπεδο που πρέπει να κατανοείτε και να ενημερώνετε· χρησιμοποιήστε το όταν σας προσφέρει κάτι.
Σύνοψη
- Ένα image είναι ένα πρότυπο μόνο για ανάγνωση σε επίπεδα· ένα container είναι ένα αντίγραφο σε εκτέλεση με δικό του επίπεδο εγγραφής.
- Τα containers μοιράζονται τον kernel του host και απομονώνονται με namespaces και cgroups: ελαφρύτερα από μια VM, αλλά με λιγότερο αυστηρό διαχωρισμό.
- Το επίπεδο εγγραφής είναι εφήμερο: τα μόνιμα δεδομένα ανήκουν σε volume ή bind mount, και αυτά ανήκουν στα αντίγραφα ασφαλείας σας.
- Ένα tag μπορεί να αλλάξει, ένα digest όχι· το
latestλέει ελάχιστα. - Δημοσιεύετε θύρες στο 127.0.0.1 και χρησιμοποιείτε μόνο images του δημιουργού ή επίσημα images.
Κουίζ
Άσκηση
Άσκηση O9.1: Container ή όχι; Επιλέξτε δύο προγράμματα που θέλετε να εκτελείτε στον server σας (ή χρησιμοποιήστε ως παράδειγμα το Uptime Kuma και έναν ιστότοπο WordPress). Για κάθε πρόγραμμα αναζητήστε αν ο δημιουργός παρέχει επίσημο image και με ποιο όνομα, ποιο tag θα επιλέγατε, ποιος φάκελος περιέχει τα μόνιμα δεδομένα και σε ποια θύρα ακούει. Στη συνέχεια εξηγήστε αν θα το εκτελούσατε σε container ή από την πηγή πακέτων, και γιατί.
Άσκηση O9.1: Container ή όχι;
Αυτή την άσκηση την κάνετε μόνοι σας: κανείς δεν την ελέγχει. Σημειώστε τι έχετε κάνει και επισημάνετε την άσκηση ως ολοκληρωμένη.
Uptime Kuma: louislam/uptime-kuma με tag έκδοσης, δεδομένα στο /app/data, θύρα 3001, δημοσίευση στο 127.0.0.1 πίσω από reverse proxy. Επιλέξτε ένα image του δημιουργού ή ένα Official Image, με tag έκδοσης και έναν επώνυμο φάκελο δεδομένων.
Τα τικ και οι σημειώσεις σας παραμένουν μόνο σε αυτό το πρόγραμμα περιήγησης· δεν τα στέλνουμε πουθενά. Αν έχετε εγγραφεί, αποθηκεύουμε στο Τα μαθήματά μου μόνο ότι έχετε ολοκληρώσει την άσκηση.
Για περαιτέρω μελέτη
- Τεκμηρίωση Docker, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Τεκμηρίωση Docker, Volumes: https://docs.docker.com/engine/storage/volumes/
- Τεκμηρίωση Docker, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
