This repository serves as a beginner's tutorial on Docker in Greek. It provides concise guidance on Docker fundamentals, including the creation of Dockerfiles, building images, running containers and sharing images.
- Εισαγωγή στο Docker
- Εγκατάσταση του Docker
- Βασικές εντολές Docker
- Κατασκευή εικόνας Docker μέσω Dockerfile
- Docker Volumes
- Docker Networking
- Case Study
Το Docker αποτελεί μια πλατφόρμα ανοικτού κώδικα που παρέχει ένα σύνολο εργαλείων για τον αυτοματισμό της διαδικασίας ανάπτυξης, δοκιμής, εγκατάστασης, ρύθμισης και εκτέλεσης εφαρμογών μέσω της χρήσης ελαφρών(lightweight), φορητών εικονικών μηχανών, γνωστών ως "containers".
- Docker Engine(Docker Client & Server)
- Η αρχιτεκτονική του Docker, όπως αποτυπώνεται παρακάτω στην εικόνα που ακολουθεί, έχει client-server δομή.
- Το/Τα Docker client(s) επικοινωνεί/ούν με τον Docker server(daemon), ο οποίος είναι υπέυθυνος για όλες τις επιμέρους λειτουργίες του Docker.
- Το Docker περιέχει ένα CLI(command line) εργαλείο, καθώς και ένα πλήρες RestFul API για την επικοινωνία με τον Docker daemon.
- Docker Images
- Αποτελούν εκτελέσιμα πακέτα που περιέχουν την εφαρμογή, τις εξαρτήσεις και τις "οδηγίες" εκτέλεσης. Πρόκειται, ουσιαστικά για τον πυρήνα - blueprint των docker containers.
- Οι εικόνες είναι αυτόνομες και μπορούν να κοινοποιούνται και να επαναχρησιμοποιούνται.
- Συνήθως οι εικόνες δημιουργούνται μέσω Dockerfile αρχείων. Πρόκειται για ένα είδος YAML αρχείου που περιγράφει τα βήματα για τη δημιουργία μιας εικόνας Docker. Περιέχει οδηγίες για την επιλογή της εικόνας βάσης, την εγκατάσταση εξαρτήσεων, τον καθορισμό του working directory και του σημείου εκκίνησης(entrypoint) κ.ά.
- Docker containers
- Πρόκειται για πλήρως αυτόνομα περιβάλλοντα εκτέλεσης(runtime environments) που ενθυλακώνουν την εφαρμογή-υπηρεσία και όλες τις απαραίτητες εξαρτήσεις της.
- Παρέχουν απομόνωση, εξασφαλίζοντας ότι η εφαρμογή εκτελείται σε ένα φορητό και ανεξάρτητο περιβάλλον, εξαλείφοντας με αυτόν τον τρόπο πιθανά προβλήματα ασυμβατότητας συστημάτων. Δηλαδή, είναι σχεδιασμένα έτσι ώστε να μπορούν να αναπτυχθούν ή να εκτελεστούν σε έναν προσωπικό υπολογιστή, σε έναν cluster στο Cloud, σε έναν virtual server ή γενικότερα σε οποιοδήποτε άλλο υπολογιστικό σύστημα.
- Docker Registry
- Το Docker αποθηκεύει και κατανέμει τα διάφορα Docker images σε αποθετήρια, τόσο δημόσια όσο και ιδιωτικά.
- Η εταιρία Docker, Inc. υποστηρίζει την κοινότητα διατηρώντας το DockerHub, το μεγαλύτερο αποθετήριο για Docker images. Πρόκειται, για μία διαδικτυακή υπηρεσία που παρέχει την δυνατότητα αποθήκευσης, διαμοιρασμού και αναζήτησης εικόνων Docker, τόσο δημοσίων όσο και ιδιωτικών.
- Ωστόσο, υπάρχει κι η δυνατότητα για κάποιον οργανισμό να υποστηρίξει ανεξάρτητο, ιδιωτικό Registry πίσω από το firewall του.
Gif source: Vikas Rajputin
Για την εγκατάσταση του Docker engine στο προσωπικό σας μηχάνημα, θα πρέπει να ακολουθήσετε συγκεκριμένα βήματα, κατάλληλα προσαρμοσμένα στο λειτουργικό σύστημα που χρησιμοποιείτε.
- Αναλυτικές οδηγίες εγκατάστασης για Windows: Docker Desktop for Windows
- Αναλυτικές οδηγίες εγκατάστασης για Linux(Ubuntu distr.): Docker Desktop for Linux
- Αναλυτικές οδηγίες εγκατάστασης για macOS: Docker Desktop for macOS
Μόλις ολοκληρώσετε την εγκατάσταση του Docker, ελέγξτε ότι η τελευταία έγινε επιτυχημένα εκτελώντας την εντολή:
$ docker run hello-world
Προκειμένου να ελέγξετε την έκδοση του Docker που έχετε πλέον στο μηχάνημά σας, μπορείτε να χρησιμοποιήσετε την εντολή:
$ docker version
Warning
Επειδή το Docker χρησιμοποιεί Unix socket το οποίο ανήκει στον root χρήστη του μηχανήματος, η χρήση του Docker CLI(Command Line) απαιτεί την χρήση του προσδιορισμού sudo. Σε περίπτωση που κάτι τέτοιο δεν είναι επιθυμητό, χρειάζεται να προσθέσετε τον αντίστοιχο χρήστη σε ένα Unix group με την ονομασία docker. Η παραπάνω διαδικασία μπορεί να διεκπεραιωθεί μέσω της εκτέλεσης των παρακάτω εντολών:
# Δημιουργία του group docker(αν δεν υπάρχει ήδη)
$ sudo groupadd docker
# Προσθήκη του χρήστη στο group docker
$ sudo usermod -aG docker $USER
# Ενεργοποίηση αλλαγών για τα groups κάνοντας relogin και ελέγχος χρήσης docker χωρίς sudo
$ docker run hello-world
Caution
Η εισαγωγή ενός χρήστη στο group Docker, του αναθέτει αυτόματα δικαιώματα επιπέδου διαχειριστή(root privileges). Επομένως, απαιτείται ιδιαίτερη προσοχή στους χρήστες που εισέρχονται στο συγκεκριμένο group.
Note
Παρέχεται και η δυνατότητα χρήσης του Docker σε rootless mode. Περισσότερες πληροφορίες μπορούν να αντληθούν από το επίσημο documentation του Docker.
✨docker pull [desired image]: Kατεβάζει την επιθυμητή εικόνα από το προεπιλεγμένο Docker registry(από το Docker Hub στην default περίπτωση) και την αποθηκεύει στο σύστημα του χρήστη. Για παράδειγμα, εκτελώντας την εντολή:
$ docker pull nginx
κατεβάζουμε και αποθηκεύουμε την εικόνα nginx στο μηχάνημά μας.
✨docker images: Εμφανίζει πληροφορίες σχετικές με τις εικόνες Docker που έχει ο χρήστης στο σύστημά του. Εάν, νωρίτερα εκτελέσατε την εντολή αποθήκευσης της εικόνας nginx, τότε εκτελώντας την εντολή:
$ docker images
θα πρέπει να λάβετε ως αποτέλεσμα μία λίστα με μία ή περισσότερες εικόνες(εάν έχετε ήδη και άλλες εικόνες στο μηχάνημά σας), μεταξύ των οποίων περιλαμβάνεται και αυτή του Nginx.
✨docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]: Χρησιμοποιείται για την δημιουργία ενός container βάσει μιας συγκεκριμένης εικόνας. Αν είναι επιθυμητός ο καθορισμός επιπλέον επιλογών, παρέχεται η δυνατότητα χρήσης επιπλέον ορισμάτων. Αυτά καθορίζουν λειτουργίες όπως το αν το container θα εκτελεστεί σε background ή interactive κατάσταση, το port-forwading συγκεκριμένων θυρών, ο μηχανισμός των logs(logging driver), κ.ά. Για παράδειγμα, εκτελώντας την εντολή:
$ docker run -d --name my_first_container -p 8080:80 nginx
δημιουργούμε ένα container που ονομάζεται my_first_container και χρησιμοποιούμε το flag -d προκειμένου το container να εκτελείται στο background, χωρίς να βλέπουμε το αποτέλεσμα πιθανής εξόδου στην οθόνη και το flag -p 8080:80 προκειμένου να συνδέσουμε τη θύρα 8080 του host συστήματος με τη θύρα 80 του container.
✨docker ps: Εμφανίζει μία λίστα με τα ενεργά containers μαζί με πληροφορίες για αυτά, όπως το container ID, το όνομα, την κατάσταση του container, τις πόρτες που χρησιμοποιεί κ.ά. Για παράδειγμα, εκτελώντας, στο προσωπικό μας μηχάνημα την εντολή:
$ docker ps
θα λάβουμε ως επιστροφή μία λίστα όπως η παρακάτω:
Παρατηρούμε πως έχουμε ένα ενεργό container(πρόκειται για εκείνο που δημιουργήσαμε νωρίτερα), το οποίο στηρίζεται στην εικόνα του Nginx και "ακούει" στην θύρα 80.
✨docker ps -a: Εμφανίζει μία λίστα με όλα τα containers του συστήματος του χρήστη μαζί με τις αντίστοιχες πληροφορίες τους.
✨docker stop [OPTIONS] CONTAINER [CONTAINER...]: Χρησιμοποιείται για να σταματήσει ένα ενεργό container. Όταν εκτελεστεί αυτή η εντολή, το Docker στέλνει ένα σήμα(SIGTERM) στις διεργασίες που τρέχουν εντός του container, προκειμένου να προετοιμαστούν για τον τερματισμό τους. Αν η μία από τις διαδικασίες αυτές δεν τερματίσει εθελοντικά, τότε έπειτα από ένα χρονικό όριο, το Docker στέλνει ένα SIGKILL για να την εξαναγκάσει να τερματίσει. Με άλλα λόγια, η εντολή docker stop σταματά ενα container, επιτρέποντάς του να ολοκληρώσει τις εκκρεμότητές του πριν τεθεί σε ανενεργή κατάσταση. Για παράδειγμα, εκτελώντας την εντολή:
$ docker stop my_first_container
σταματά το container "my_first_container" και τίθεται σε ανενεργή κατάσταση. Η ανενεργή κατάσταση του container μπορεί να επιβεβαιωθεί μέσω της εκτέλεσης της εντολής docker ps -a.
✨docker start [OPTIONS] CONTAINER [CONTAINER...]: Χρησιμοποιείται για την εκκίνηση ενός προηγουμένως δημιουργημένου, αλλά σταματημένου container. Όταν ένα container τερματίζεται(σταματημένο), τότε σταματά να εκτελείται και έτσι δεν καταναλώνει πόρους του συστήματος. Η εντολή docker start επανεκκινεί το container, επιτρέποντάς του να να εκκινήσει ξανά την εκτέλεσή του. Για παράδειγμα, εκτελώντας την εντολή:
$ docker start my_first_container
εκκινείται το container "my_first_container" και τίθεται σε ενεργή κατάσταση. Η ενεργή κατάσταση του container μπορεί να επιβεβαιωθεί μέσω της εκτέλεσης της εντολής docker ps.
✨docker exec [OPTIONS] CONTAINER COMMAND [ARG...]: Χρησιμοποιείται για την εκτέλεση εντολών εντός ενός ενεργού container. Επιτρέπει έτσι στους χρήστες να εκτελούν εντολές ή να αλληλεπιδρούν με το εσωτερικό περιβάλλον ενός container. Για παράδειγμα, εκτελώντας την εντολή:
$ docker exec my_first_container nginx -v
λαμβάνουμε την έκδοση του Nginx server που εκτελείται μέσα στο container "my_first_container".
✨docker attach [OPTIONS] CONTAINER: Χρησιμοποιείται για την σύνδεση του χρήστη με τα I/O streams του τερματικού ενός ενεργού container, επιτρέποντάς την απευθείας επικοινωνία του με το περιβάλλον εκτέλεσης του container. Για παράδειγμα, εκτελώντας τις εντολές:
$ docker attach my_first_container
$ curl -sSL http://127.0.0.1:8080
συνδεόμαστε στο stdout της διεργασίας nginx του container "my_first_container" και παρατηρούμε το αίτημα που έλαβε ο nginx server του container από την εκτέλεση της δεύτερης εντολής.
Note
Η εκτέλεση της εντολής docker attach μπορεί να μοιάζει κάποιες φορές ως μη απόκριση του συστήματος, αλλά αυτό μπορεί να οφείλεται στην έλλειψη δεδομένων στο Ι/Ο stream του τερματικού στο οποίο συνδέθηκε.
Important
Επειδή με την εντολή docker attach γίνεται σύνδεση πχ στο stdout της διεργασίας του container, ο τερματισμός της τρέχουσας διεργασίας(με τη χρήση CTRL + C - σήμα SIGINT) ισοδυναμεί επίσης και με τον τερματισμό του container.
✨docker inspect [OPTIONS] NAME|ID [NAME|ID...]: Επιστρέφει ένα JSON αντικείμενο που περιέχει λεπτομερείς πληροφορίες για ένα ή περισσότερα αντικείμενα Docker, όπως είναι containers, images, networks και volumes.
✨docker logs [OPTIONS] CONTAINER: Χρησιμοποιείται για την εμφάνιση των δεδομένων κάποιου I/O stream της διεργασίας ενός ενεργού ή πρόσφατα τερματισμένου container, σύμφωνα με τον logging driver που έχει οριστεί για αυτό. Αν δεν επιλεχθεί κάποια πιο σύνθετη ρύθμιση, η εντολή δείχνει την έξοδο στο stdout της διεργασίας του container αυτού.
✨docker rm [OPTIONS] CONTAINER [CONTAINER...]: Χρησιμοποιείται για την διαγραφή ενός ή περισσότερων containers που έχουν τερματιστεί από το σύστημα. Χρησιμοποιείται, επομένως, για την αφαίρεση των container instances που δεν χρειάζεται ο χρήστης πλέον. Για παράδειγμα, εκτελώντας την εντολή:
$ docker rm my_first_container
θα διαγράψουμε το container με το όνομα "my_first_container". Εάν θέλουμε να διαγράψουμε περισσότερα από ένα container, τοποθετούμε τα ονόματά τους ως επιπλέον ορίσματα. Η διαγραφή του container μπορεί να επιβεβαιωθεί μέσω της εκτέλεσης της εντολής docker ps.
Tip
Χρησιμοποιώντας το flag -f στην εντολή docker rm -f my_first_container το container "my_first_container" θα διαγραφεί ακόμη και αν είναι ενεργό, αλλά αυτό ενδεχομένως να οδηγήσει σε απώλεια δεδομένων ή προβλήματα, αν δεν έχει εκτελεστεί προηγουμένως κατάλληλος έλεγχος.
Όπως αναφέρθηκε νωρίτερα, ένα Dockerfile είναι ένα αρχείο τύπου YAML με ένα σύνολο από βήματα(instructions) μιας γλώσσας ειδικού πεδίου(Domain Specific language) που κατευθύνουν τη δημιουργία μιας εικόνας Docker.
Για να γίνει κατανοητός ο τρόπος με τον οποίο δομείται ένα τέτοιο αρχείο, θα δημιουργηθεί ένα Dockerfile για την κατασκευή εικόνας η οποία θα περιγράφει το container μίας απλής Web εφαρμογής. Πιο συγκεκριμένα, θα γίνει deploy ένα container τοπικά, στο οποίο θα εκτελείται μία εφαρμογή γραμμένη με Express-Node.js, σκοπός της οποίας είναι η εξυπηρέτηση ενός endpoint. Σ'αυτό, η εφαρμογή θα δέχεται HTTP POST αιτήσεις με δεδομένα σε μορφή JSON, τα οποία ακολούθως θα αποθηκεύει στον server.
Το αρχείο Dockerfile δομείται ως εξής:
# Χρησιμοποιούμε μια επίσημη εικόνα του Node.js ως βάση. Το tag latest προσδιορίζει ότι "κατεβάζουμε" την πιο πρόσφατα διαθέσιμη επίσημη εικόνα Node.js
FROM node:latest
# Metadata στην εικόνα
LABEL maintainer="Argiris Sofotasios & Dimitris Metaxakis"
LABEL description="A simple Web app."
# Ορισμός environment variable για χρήση της από την εφαρμογή
ENV NODE_PORT=8891
# Δηλώνουμε τον φάκελο εργασίας στο περιβάλλον του container
WORKDIR /app
# Αντιγράφουμε τα αρχεία της εφαρμογής στον container
COPY . /app
# Εγκατάσταση των απαραίτητων βιβλιοθηκών
RUN npm install express body-parser
# Καθορισμός της θύρας που θα ακούει το container
EXPOSE 8891
# Κατά την εκκίνηση του container τρέχει ο server καλώντας το binary executable του nodejs
ENTRYPOINT ["node", "server.js"]
Δημιουργία της εικόνας nodejs_server:
cd ./casestudies/CaseStudy1/src
docker build -t nodejs_server:v0.1 .
Note
Ο προσδιορισμός . ενημερώνει τον docker deamon για το build context της εικόνας, δηλαδή το σύνολο των αρχείων και φακέλων που εντοπίζονται σε αυτό. Την πληροφορία αυτή την χρησιμοποιεί ο deamon μεταξύ άλλων για την πρόσβαση σε αρχεία που μπορεί να χρησιμοποιούνται από εντολές στο Dockerfile καθώς και για την αποδοτική δημιουργία νέων εικονών με την χρήση έξυπνων caching μηχανισμών.
Δημιουργία και εκτέλεση του container express_server:
docker run -d --name express_server -p 8080:8891 nodejs_server:v0.1
Στον κορμό του, ένα Docker container χρησιμοποιεί ένα πολυεπίπεδο ιεαραρχικό σύστημα αρχείων(layered file system). Κάθε επίπεδο-στρώμα αντιπροσωπεύει ένα σύνολο από αλλαγές στα αρχεία. Τα επίπεδα αυτά στοιβάζονται το ένα πάνω στο άλλο με σκοπό την δημιουργία του τελικού συστήματος αρχείων του container. Μολονότι αυτή η προσέγγιση έχει ένα πλήθος πλεονεκτημάτων, μια βασική της αδυναμία είναι η διαγραφή των επιπέδων αυτών και των αντίστοιχων αρχείων κατά την διαγραφή ενός container.
Layered FS visualizationΤα docker volumes είναι ένας μηχανισμός που εισάγεται για την διαχείριση του ζητήματος αυτού, καθώς αυτά παρακάμπτουν το ιεραρχικό σύστημα αρχείων. Πρόκειται για ειδικά ορισμένους καταλόγους που έχουν σκοπό τον διαμοιρασμό και την διατήρηση δεδομένων μεταξύ των διαφόρων containers, ανεξάρτητα από τον κύκλο ζωής τους.
Στην δική μας εφαρμογή, o server αποθηκεύει τα δεδομένα των εισερχόμενων HTTP αιτήσεων σε ένα JSON αρχείο. Επειδή το αρχείο αυτό είναι αποθηκευμένο σε ένα στρώμα(layer) στο περιβάλλον του container, όταν το container διαγραφτεί, θα διαγραφτεί κι αυτό μαζί του. Συνεπώς, θα χάσουμε τα δεδομένα του server. Για να αποφευχθεί η ανεπιθύμητη αυτή κατάσταση, δημιουργούμε έναν καινούριο κατάλογο data_per, δημιουργούμε ένα volume, έτσι ώστε να κάνουμε mount(συνδέσουμε) τον τοπικό κατάλογό μας CaseStudy1/data_per στον κατάλογο opt/data_per του container, εκτελώντας την παρακάτω εντολή κατά τη δημιουργία του container:
cd ./case_studies/CaseStudy1/
mkdir data_per
docker run -d --name express_server -p 8080:8891 --mount type=bind,source="$(pwd)"/data_per,target=/opt/data_per nodejs_server:v0.1
Ισοδύναμα η τρίτη εντολή μπορεί να γραφτεί και ως εξής:
docker run -d --name express_server -p 8080:8891 -v "$(pwd)"/data_per:/opt/data_per nodejs_server:v0.1
Με τον τρόπο αυτό δημιουργούμε ένα bind mount. Πρόκειται για μια γρήγορη τεχνική που χρησιμοποιείται συχνά από τους developers, ωστόσο η λειτουργία της στηρίζεται σε μεγάλο βαθμό στη δομή του συστήματος αρχείων(FS) του host με αποτέλεσμα να προκαλεί σημαντικά προβλήματα απόδοσης.
Εκτός από τα bind mounts που καθορίζονται συναρτήσει της ύπαρξης ενός container, υπάρχει και η δυνατότητα δημιουργίας volumes ανεξάρτητα από τα διάφορα containers.
Τέτοιου είδους volumes μπορούν να δημιουργηθούν με την εκτέλεση της εντολής:
docker volume create [volume name]
Όλα τα volumes που διαθέτει ο χρήστης στο σύστημά του μπορούν να εμφανιστούν με την εκτέλεση της εντολής:
docker volume ls
ενώ η επισκόπηση των πληροφοριών ενός συγκεκριμένου volume είναι εφικτή μέσω της εκτέλεσης της εντολής:
docker volume inspect [volume name]
Τέλος η διαγραφή ενός volume, εφόσον δεν υπάρχει ενεργό container που να το χρησιμοποιεί, πραγματοποιείται με την εκτέλεση της εντολής:
docker volume rm [volume name]
Το Docker Networking εισήχθει στην έκδοση 1.9 επιτρέποντας την εκτενή εξατομίκευση της δικτύωσης μεταξύ των containers. Το Docker πλέον παρέχει την δυνατότητα ορισμού προσαρμοσμένων δικτύων από το χρήστη, καθιστώντας έτσι δυνατή την σύνδεση πολλαπλών containers στο ίδιο δίκτυο. Κάθε container έχει τη δική του διεύθυνση IP και το δικό του namespace εντός του δικτύου στο οποίο ανήκει. Αφού συνδεθούν στο user-defined δίκτυο, τα containers μπορούν να επικοινωνούν μεταξύ τους χρησιμοποιώντας τις IP διευθύνσεις τους ή τα ονόματά τους, τα οποία διαχειρίζονται πλήρως από ένα σύστημα ονοματοδοσίας(DNS) του Docker.
Το Docker Networking είναι pluggable, παρέχοντας ένα σύνολο από Drivers, κάθε ένας εκ των οποίων προσφέρει εξειδικευμένη λειτουργικότητα. Οι πιο δημοφιλείς από αυτούς είναι:
-
Bridge: Πρόκειται για τον προκαθορισμένο(default) network driver. Συνήθως χρησιμοποιείται σε περιπτώσεις που υπάρχει ανάγκη επικοινωνίας μεταξύ διαφορετικών containers του ίδιου host. Είναι μία συσκευή επιπέδου ζεύξης που προωθεί την κίνηση μεταξύ τμημάτων δικτύου. Ο Docker bridge driver εγκαθιστά αυτόματα κανόνες στο σύστημα του host, ούτως ώστε τα containers που ανήκουν σε διαφορετικά bridged networks να μην μπορούν να επικοινωνήσουν άμεσα μεταξύ τους. Κατά την εκκίνηση του Docker, δημιουργείται ένα προεπιλεγμένο bridged δίκτυο στο οποίο συνδέονται όλα τα containers. Κάτι τέτοιο παύει να ισχύει, εάν ο χρήστης καθορίσει το δίκτυο που θα συνδεθεί το αντίστοιχο container.
-
Host: Άρει την συνθήκη απομόνωσης της στοίβας δικτύου του αντίστοιχου container, το οποίο πλέον δεν έχει δική του IP διεύθυνση αλλά μοιράζεται το ίδιο namespace δικτύου με τον host, χωρίς την εφαρμογή NAT(Network Address Translation). Οι υπηρεσίες των εφαρμογών του container γίνονται πλέον διαθέσιμες μέσω της IP του host στις θύρες τις οποίες κάνει EXPOSE το container. Συνεπώς, το port-mapping με το argument -p κατά τη δημιουργία του container(με χρήση του command run) παύει να έχει ισχύ.
-
Overlay: Δημιουργεί ένα κατανεμημένο δίκτυο μεταξύ πολλαπλών docker deamon hosts. Το δίκτυο αυτό περιβάλλει το δίκτυο του κάθε host, δίνοντας έτσι τη δυνατότητα επικοινωνίας μεταξύ containers (που εν δυνάμει ανήκουν σε διαφορετικούς hosts) που είναι συνδεδεμένα σε αυτό. Η μεταφορά πακέτων-μηνυμάτων μεταξύ Docker daemon host και container παραλήπτη διεκπεραιώνεται με πλήρη διαφάνεια από το Docker, παρέχοντας επίσης την δυνατότητα για κρυπτογράφηση για την επίτευξη ασφάλειας.
[!INFORMATION] Ο Overlay Driver χρησιμοποιείται κυρίως για τη διασύνδεση πολλαπλών υπηρεσιών Swarm, ένας μηχανισμός που υπάγεται στο Docker Swarm mode, το οποίο δεν καλύπτεται στο παρόν tutorial.