Skip to content

DockerTutorialGR: 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 data between them.

Notifications You must be signed in to change notification settings

Sofosss/DockerTutorialGR

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 

Repository files navigation


logo
A GR Docker Tutorial for Beginners

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 data between them.


License

🚩 Περιεχόμενα

Εισαγωγή στο Docker

Τι είναι το Docker

Το Docker αποτελεί μια πλατφόρμα ανοικτού κώδικα που παρέχει ένα σύνολο εργαλείων για την αυτοματοποίηση της διαδικασίας ανάπτυξης, δοκιμών, εγκατάστασης, ρύθμισης και εκτέλεσης εφαρμογών μέσω της χρήσης ελαφρών (lightweight), φορητών εικονικών μηχανών, γνωστών ως "containers".

Βασικά στοιχεία

  1. Docker Engine (Docker Client & Server)
  • Η αρχιτεκτονική του Docker, όπως αποτυπώνεται στην εικόνα που ακολουθεί, έχει client-server δομή.
  • Το/Τα Docker client(s) επικοινωνεί/ούν με τον Docker server (daemon), ο οποίος είναι υπέυθυνος για όλες τις επιμέρους λειτουργίες του Docker.
  • Το Docker περιέχει ένα CLI (command line) εργαλείο, καθώς και ένα πλήρες RestFul API για την επικοινωνία με τον Docker daemon.
  1. Docker Images
  • Αποτελούν εκτελέσιμα πακέτα που περιέχουν την εφαρμογή, τις εξαρτήσεις και τις "οδηγίες" εκτέλεσης. Πρόκειται, ουσιαστικά για τον πυρήνα - blueprint των Docker containers.
  • Οι εικόνες είναι αυτόνομες και μπορούν να κοινοποιούνται και να επαναχρησιμοποιούνται.
  • Συνήθως οι εικόνες δημιουργούνται μέσω Dockerfile αρχείων. Πρόκειται για ένα είδος YAML αρχείου που περιγράφει τα βήματα για τη δημιουργία μιας Docker εικόνας. Περιέχει οδηγίες για την επιλογή της εικόνας βάσης, την εγκατάσταση εξαρτήσεων, τον καθορισμό του working directory και του σημείου εκκίνησης (entry point) κ.ά.
  1. Docker containers
  • Πρόκειται για πλήρως αυτόνομα περιβάλλοντα εκτέλεσης (runtime environments) που ενθυλακώνουν την εφαρμογή-υπηρεσία και όλες τις απαραίτητες εξαρτήσεις της.
  • Παρέχουν απομόνωση, εξασφαλίζοντας ότι η εφαρμογή εκτελείται σε ένα φορητό και ανεξάρτητο περιβάλλον, εξαλείφοντας με αυτόν τον τρόπο πιθανά προβλήματα ασυμβατότητας συστημάτων. Είναι, δηλαδή, σχεδιασμένα με τρόπο τέτοιο έτσι ώστε να μπορούν να αναπτυχθούν/εκτελεστούν σε έναν (οποιοδήποτε) προσωπικό υπολογιστή, σε έναν cluster στο Cloud, σε έναν virtual server και γενικότερα σε οποιοδήποτε υπολογιστικό σύστημα.
  1. Docker Registry
  • Το Docker αποθηκεύει και κατανέμει τα διάφορα Docker images σε αποθετήρια, τόσο δημόσια όσο και ιδιωτικά.
  • Η εταιρία Docker Inc. υποστηρίζει την κοινότητα διατηρώντας το Docker Hub, το μεγαλύτερο αποθετήριο για Docker images. Πρόκειται για μία διαδικτυακή υπηρεσία που παρέχει την δυνατότητα αποθήκευσης, διαμοιρασμού και αναζήτησης εικόνων Docker, τόσο δημόσιων όσο και ιδιωτικών.
  • Υπάρχει, ωστόσο, και η δυνατότητα για κάποιον οργανισμό να υποστηρίξει ανεξάρτητο, ιδιωτικό Registry πίσω από το firewall του για την εσωτερική διαχείριση των Docker εικόνων. Αυτό σημαίνει ότι ο οργανισμός μπορεί να διατηρεί τις Docker εικόνες του (π.χ., εικόνες που χρησιμοποιούνται για τις εφαρμογές του) σε ένα ιδιωτικό αποθετήριο (Registry) που είναι προσβάσιμο μόνο από το εσωτερικό δίκτυο του οργανισμού.


docker_architecture
Gif source: Vikas Rajputin


Εγκατάσταση του Docker

Για την εγκατάσταση του Docker engine στον προσωπικό σας υπολογιστή , θα πρέπει να ακολουθήσετε συγκεκριμένα βήματα, κατάλληλα προσαρμοσμένα στο λειτουργικό σύστημα που χρησιμοποιείτε.

Μόλις ολοκληρώσετε την εγκατάσταση του 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

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 

θα λάβουμε ως επιστροφή μία λίστα όπως η παρακάτω:

docker_ps result img

Παρατηρούμε πως έχουμε ένα ενεργό 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" και τίθεται σε ενεργή κατάσταση που μπορεί να επιβεβαιωθεί μέσω της εντολής 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". Εάν θέλουμε να διαγράψουμε περισσότερα από ένα containers, τοποθετούμε τα ονόματά τους ως επιπλέον ορίσματα. Η διαγραφή του container μπορεί να επιβεβαιωθεί μέσω της εντολής docker ps.

Tip

Χρησιμοποιώντας το flag -f στην εντολή docker rm -f my_first_container το container "my_first_container" θα διαγραφεί ακόμη και αν είναι ενεργό, αλλά αυτό ενδεχομένως να οδηγήσει σε απώλεια δεδομένων ή άλλα προβλήματα, αν δεν έχει εκτελεστεί προηγουμένως κατάλληλος έλεγχος.

Κατασκευή εικόνας Docker μέσω Dockerfile

Όπως αναφέρθηκε νωρίτερα, ένα Dockerfile είναι ένα αρχείο τύπου YAML με ένα σύνολο από βήματα (instructions) μιας γλώσσας ειδικού πεδίου (Domain Specific Language) που κατευθύνουν τη δημιουργία μιας εικόνας Docker.

Για να γίνει κατανοητός ο τρόπος με τον οποίο δομείται ένα τέτοιο αρχείο, θα δημιουργηθεί ένα Dockerfile για την κατασκευή εικόνας η οποία θα περιγράφει το container μίας απλής Web εφαρμογής. Πιο συγκεκριμένα, θα γίνει deploy ένα container τοπικά, στο οποίο θα εκτελείται μία εφαρμογή γραμμένη με Express-Node.js, σκοπός της οποίας είναι η εξυπηρέτηση ενός endpoint. Στο endpoint, η εφαρμογή θα δέχεται HTTP POST αιτήσεις με δεδομένα μορφής JSON, τα οποία ακολούθως θα αποθηκεύει στον server (σε τοπικό αρχείο τύπου JSON του container).

Το αρχείο 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 daemon για το build context της εικόνας, δηλαδή το σύνολο των αρχείων και φακέλων που εντοπίζονται σε αυτό. Την πληροφορία αυτή την χρησιμοποιεί ο daemon μεταξύ άλλων για την πρόσβαση σε αρχεία που μπορεί να ορίζονται από εντολές στο Dockerfile καθώς και για την αποδοτική δημιουργία νέων εικόνων με την χρήση έξυπνων caching μηχανισμών.

Δημιουργία και εκτέλεση του container express_server:

docker run -d --name express_server -p 8080:8891 nodejs_server:v0.1 

Docker Volumes

Στον κορμό του, ένα Docker container χρησιμοποιεί ένα πολυεπίπεδο ιεραρχικό σύστημα αρχείων (layered file system). Κάθε επίπεδο-στρώμα αντιπροσωπεύει ένα σύνολο από αλλαγές στα αρχεία. Τα επίπεδα αυτά στοιβάζονται το ένα πάνω στο άλλο με σκοπό την δημιουργία του τελικού συστήματος αρχείων του container. Μολονότι αυτή η προσέγγιση έχει ένα πλήθος πλεονεκτημάτων, μια βασική της αδυναμία είναι η διαγραφή των επιπέδων αυτών και των αντίστοιχων αρχείων κατά την διαγραφή ενός container.


docker_architecture
Layered FS visualization


Τα Docker volumes είναι μηχανισμός που εισάγεται για την διαχείριση του ζητήματος αυτού, καθώς τα volumes παρακάμπτουν το ιεραρχικό σύστημα αρχείων. Πρόκειται για ειδικά ορισμένους καταλόγους που έχουν σκοπό τον διαμοιρασμό και την διατήρηση δεδομένων μεταξύ των διαφόρων containers, ανεξάρτητα από τον κύκλο ζωής τους.

Στην δική μας εφαρμογή, o server αποθηκεύει τα δεδομένα των εισερχόμενων HTTP αιτήσεων σε ένα JSON αρχείο. Επειδή το αρχείο αυτό είναι αποθηκευμένο σε ένα στρώμα (layer) στο περιβάλλον του container, όταν το container διαγραφεί, θα διαγραφεί κι αυτό μαζί του. Συνεπώς, θα χάσουμε τα δεδομένα του server. Για να αποφευχθεί η ανεπιθύμητη αυτή κατάσταση, δημιουργούμε έναν καινούριο κατάλογο data_per και μέσω ενός Docker 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, ωστόσο η λειτουργία της στηρίζεται σε μεγάλο βαθμό στη δομή του συστήματος αρχείων του host με αποτέλεσμα να προκαλεί σημαντικά προβλήματα απόδοσης.

Εκτός από τα bind mounts που καθορίζονται συναρτήσει της ύπαρξης ενός container, υπάρχει και η δυνατότητα δημιουργίας volumes ανεξάρτητα από τα διάφορα containers.

Τέτοιου είδους volumes μπορούν να δημιουργηθούν με την εκτέλεση της εντολής:

docker volume create [OPTIONS] [VOLUME]

Όλα τα volumes που διαθέτει ο χρήστης στο σύστημά του μπορούν να εμφανιστούν με την εκτέλεση της εντολής:

docker volume ls [OPTIONS]

ενώ η επισκόπηση των πληροφοριών ενός συγκεκριμένου volume είναι εφικτή με την εκτέλεση της εντολής:

docker volume inspect [OPTIONS] VOLUME [VOLUME...]

Η διαγραφή ενός volume, εφόσον δεν υπάρχει ενεργό container που το χρησιμοποιεί, πραγματοποιείται με την εκτέλεση της εντολής:

docker volume rm [OPTIONS] VOLUME [VOLUME...]

Τέλος, η διαγραφή όλων των αχρησιμοποίητων (unused) volumes του συστήματος πραγματοποιείται με την εκτέλεση της εντολής:

docker volume prune [OPTIONS]

Docker Networking

Το Docker Networking εισήχθη στην έκδοση 1.9 επιτρέποντας την εκτενή εξατομίκευση της δικτύωσης μεταξύ των containers. Το Docker πλέον παρέχει την δυνατότητα ορισμού προσαρμοσμένων δικτύων από το χρήστη, καθιστώντας έτσι δυνατή την σύνδεση πολλαπλών containers στο ίδιο δίκτυο. Κάθε container έχει τη δική του διεύθυνση IP και το δικό του namespace εντός του δικτύου στο οποίο ανήκει. Αφού συνδεθούν στο user-defined δίκτυο, τα containers μπορούν να επικοινωνούν μεταξύ τους χρησιμοποιώντας τις IP διευθύνσεις τους ή τα ονόματά τους ενώ η διαχείρισή τους γίνεται από το σύστημα ονοματοδοσίαs (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 με το όρισμα -p κατά τη δημιουργία του container (με χρήση της εντολής run) παύει να ισχύει.

  • Overlay: Δημιουργεί ένα κατανεμημένο δίκτυο μεταξύ πολλαπλών Docker daemon hosts. Το δίκτυο αυτό περιβάλλει το δίκτυο του κάθε host, δίνοντας έτσι τη δυνατότητα επικοινωνίας μεταξύ containers (που εν δυνάμει ανήκουν σε διαφορετικούς hosts) που είναι συνδεδεμένα σε αυτό. Η μεταφορά πακέτων-μηνυμάτων μεταξύ Docker daemon host και container-παραλήπτη διεκπεραιώνεται με πλήρη διαφάνεια από το Docker ενώ παρέχεται και η δυνατότητα για κρυπτογράφηση για μεγαλύτερη ασφάλεια.

Important

Ο Overlay driver είναι μηχανισμός που χρησιμοποιείται κυρίως για τη διασύνδεση πολλαπλών υπηρεσιών Swarm και υπάγεται στο Docker Swarm mode, το οποίο δεν καλύπτεται στο παρόν tutorial.

Προκειμένου να κατασκευάσουμε ένα Docker δίκτυο αρκεί να εκτελέσουμε την εντολή:

docker network create [OPTIONS] NETWORK

Η δημιουργία και η ένταξη ενός container σε ένα συγκεκριμένο δίκτυο, πραγματοποιείται με την εκτέλεση της εντολής:

docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

Όλα τα networks που διαθέτει ο χρήστης στο σύστημά του μπορούν να εμφανιστούν με την εκτέλεση της εντολής:

docker network ls [OPTIONS]

ενώ η επισκόπηση των πληροφοριών ενός συγκεκριμένου network είναι εφικτή μέσω της εντολής:

docker network inspect [OPTIONS] NETWORK [NETWORK...]

Η σύνδεση ενός container σε ένα συγκεκριμένο network είναι εφικτή μέσω της εντολής:

docker network connect [OPTIONS] NETWORK CONTAINER

Η αποσύνδεση ενός container από ένα network είναι εφικτή μέσω της εντολής:

docker network disconnect [OPTIONS] NETWORK CONTAINER

Η διαγραφή ενός συγκεκριμένου network, εφόσον δεν υπάρχει ενεργό container που ανήκει σε αυτό, πραγματοποιείται με την εκτέλεση της εντολής:

docker network rm NETWORK [NETWORK...]

Τέλος, η διαγραφή όλων των ανενεργών δικτύων του συστήματος πραγματοποιείται με την εκτέλεση της εντολής:

docker network prune [OPTIONS]

Η εντολή αυτή είναι χρήσιμη για τον καθαρισμό του συστήματός σας από δίκτυα που δεν χρησιμοποιούνται πλέον, εξοικονομώντας έτσι χώρο και πόρους.

Για να γίνει κατανοητός ο τρόπος με τον οποίο λειτουργεί ένα Docker Network, θα παρουσιάσουμε ένα παράδειγμα στο οποίο θα δημιουργείται ένα Docker Network με δύο containers. Το πρώτο container θα λειτουργεί ως server και θα έχει την λειτουργία που είχε και το αντίστοιχο container στο παράδειγμα με τα Volumes (Case Study 1). Το δεύτερο container θα λειτουργεί ως client. Μέσω κλήσης σε εξωτερικό API θα αποκτά ένα σύνολο δεδομένων, τα οποία στη συνέχεια θα στέλνει ανά τακτά χρονικά διαστήματα μέσω HTTP Requests στο server container. Όπως και στο Case study 1, το container του server θα αποθηκεύει τα δεδομένα αυτά σε ένα τύπου JSON αρχείο που είναι μόνιμο (persistent) εξαιτίας του volume που δημιουργήθηκε.

Τα Dockerfiles του συγκεκριμένου παραδείγματος βρίσκονται στον κατάλογο case_studies/CaseStudy2.

Επισημαίνεται ότι η αλληλεπίδραση του χρήστη με τον Docker daemon καθίσταται δυνατή και μέσω Docker SDK (Software Develοpment Kit) το οποίο παρέχει γλώσσες προγραμματισμού όπως η Python, οι οποίες μπορούν να χρησιμοποιηθούν για την διαχείριση και την αλληλεπίδραση με τα Docker containers. Μέσω του Docker SDK μπορούμε να εκτελέσουμε εντολές, να δημιουργήσουμε, να διαχειριστούμε και να παρακολουθήσουμε containers, εικόνες και άλλα στοιχεία του Docker.

cd CaseStudy2

# Δημιουργία Docker network
docker network create sample_network

# Δημιουργία των Docker images 
cd server
docker build -t node_image .
cd ../client
docker build -t ubuntu_client_image .

# Δημιουργία και εκκίνηση server container
cd ../
mkdir users
docker run -d --name node_server --network sample_network -v "$(pwd)"/users:/opt/user_data node_image

# Δημιουργία και εκκίνηση client container
docker run --rm -d --name node_client --network sample_network  ubuntu_client_image

Στο παρακάτω gif παρατίθενται τα logs των δύο containers (αριστερά αυτό του server και δεξιά το αντίστοιχο του client):

Παρατηρούμε ότι ο client αποκτά τα απαραίτητα δεδομένα και στη συνέχεια ανά συγκεκριμένες χρονικές στιγμές πραγματοποιεί HTTP αιτήσεις στον server παρέχοντάς του ως πληροφορία μερικές εγγραφές των δεδομένων του. Ο server λαμβάνει τις αιτήσεις του client και εγγράφει τις ληφθείσες εγγραφές σε ένα αρχείο στο volume.

Μέχρι τώρα είδαμε την επικοινωνία του Client με τον Docker daemon μέσω του CLI. Για λόγους πληρότητας, ακολούθως θα δείξουμε και ένα παράδειγμα που αξιοποιεί την δυνατότητα αλληλεπίδρασης με το Docker daemon μέσω ενός SDK στην Python. Πιο συγκεκριμένα, θα δημιουργήσουμε ένα Docker Network ως εξής:

def setup_docker_net(client, netname: str, networkOptions: dict): 
    try: 
        docker_network = client.networks.list(names = netname)

        # Επιστροφή αντικειμένου που αναπαριστά το δίκτυο σε περίπτωση που αυτό υπάρχει
        if len(docker_network) > 0:
            print(f"Network: {netname} already exists. Proceeding...")
            return docker_network[0]

        # Δημιουργία και επιστροφή του δικτύου βάσει ορισμένων παραμέτρων
        print(f"Network: {netname} does not exist. Creating...")
        ipam_pool = docker.types.IPAMPool(
            subnet = networkOptions['subnet'],
            gateway =  networkOptions['gateway'],
            iprange = networkOptions['ip_range']
        )
        ipam_config = docker.types.IPAMConfig(
            pool_configs = [ipam_pool]
        )
        return client.networks.create(netname, driver = "bridge", ipam = ipam_config)
    
    except docker.errors.APIError as e:
        print(f"Error occured while creating the network: {e}")

Case Study

Προκειμένου να χρησιμοποιήσουμε στην πράξη οτιδήποτε ειπώθηκε στο tutorial, θα εκτελέσουμε ένα τελικό case study (case_studies/CaseStudy3). Θα δημιουργήσουμε τρία containers τα οποία θα ανήκουν στο ίδιο δίκτυο (network) και θα λειτουργούν συνεργατικά για να παρέχουν μια σχετικά απλή υπηρεσία.

Το πρώτο container θα λειτουργεί ως server, διαχειρίζοντας HTTP αιτήσεις από διάφορους clients. Πιο συγκεκριμένα, θα δέχεται, αναλύει και επεξεργάζεται αιτήματα από τους χρήστες προς την υπηρεσία, θα είναι υπεύθυνο για την ταυτοποίηση χρηστών της υπηρεσίας, θα ελέγχει την πρόσβαση χρηστών σε πόρους της υπηρεσίας βάσει των JWTs(JSON Web Tokens) που διατηρούν και θα καταγράφει σε συγκεκριμένη μορφής αρχείο log πιθανή ύποπτη κίνηση εντός της υπηρεσίας. Το δεύτερο container θα στηρίζει τη βάση δεδομένων της υπηρεσίας, χρησιμοποιώντας MongoDB για την αποθήκευση των χρηστών της. Τέλος, το τρίτο container θα διαδραματίζει τον ρόλο του logger. Συγκεκριμένα, θα παρακολουθεί (monitoring) το αρχείο στο οποίο εγγράφει ο server πιθανή ύποπτη κίνηση εντός της υπηρεσίας και θα καταγράφει στο stdout (standard output) του οποιαδήποτε αλλαγή (προσθήκη εγγραφής) σ' αυτό. Η δυνατότητα αυτή θα επιτευχθεί μέσω της παρακολούθησης ενός διαμοιρασμένου αρχείου log του server με τη χρήση ενός Docker Volume.

Η παρακάτω εικόνα αποτυπώνει την αρχιτεκτονική της υπηρεσίας για τα δύο βασικά endpoints που επιθυμούμε να δημιουργήσουμε:


docker_architecture
Case Study 3 architecture


Για να υλοποιηθεί η παραπάνω υπηρεσία, θα πρέπει να εκτελέσουμε τα παρακάτω βήματα:

Αρχικά θα πρέπει να δημιουργήσουμε ένα Docker Network εντός του οποίου θα εντάξουμε αργότερα τα Docker containers που θα κατασκευάσουμε. Η δημιουργία του δικτύου γίνεται ως εξής:

docker network create cstd3

Στη συνέχεια θα δημιουργήσουμε το container που αντιστοιχεί στον server της υπηρεσίας. Η εικόνα που θα χρησιμοποιηθεί για την κατασκευή του δομείται βάσει του Dockerfile. Ο server θα "ακούει" στην θύρα 8891 και θα ανήκει στο δίκτυο cstd3. Η κατασκευή της εικόνας και η δημιουργία του container γίνεται ως εξής

cd case_studies/Casestudy3/webserver

# Κατασκευή της εικόνας του server
docker build -t fserver_image:v0.1 .

# Δημιουργία του server container
docker run -d --name fapi_server --network cstd3 -p 8891:8891 fserver_image:v0.1

Η δημιουργία του container που υποστηρίζει την λειτουργία της βάσης δεδομένων της υπηρεσίας θα στηριχθεί στην εικόνα που δομείται βάσει του Dockerfile. Προφανώς, και αυτό το container θα ανήκει στο δίκτυο cstd3. Η κατασκευή της εικόνας και η δημιουργία του container εκτελείται ως εξής:

cd case_studies/Casestudy3/db

# Κατασκευή της εικόνας του db 
docker build -t cstd_mongo_image:v0.1 .

# Δημιουργία του db container
docker run -d --name mongodb_node --network cstd3 cstd_mongo_image:v0.1

Τέλος, το τρίτο container που θα δημιουργήσουμε και θα εντάξουμε στο δίκτυο cstd3 είναι αυτό του logger. Κατά τη δημιουργία του, θα του γίνουν mount όλα τα mounted volumes του server container. Η συγκεκριμένη ενέργεια υπαγορεύεται από την ανάγκη πρόσβασης του logger container στο αρχείο που εγγράφει ο server τις παρατηρήσεις του σχετικά με πιθανή ύποπτη κίνηση στην υπηρεσία. Η εικόνα του logger container βασίζεται στο Dockerfile. Η κατασκευή της εικόνας και η δημιουργία του logger container εκτελείται ως εξής:

cd case_studies/Casestudy3/logstash

# Κατασκευή της εικόνας του logger 
docker build -t logstash_image:v0.1 .

# Δημιουργία του logger container
docker run -d --name logger --net cstd3 --volumes-from fapi_server -p 9600:9600 logstash_image:v0.1

Αφότου εκτελέσουμε τα παραπάνω βήματα, είναι εφικτό να ελέγξουμε την λειτουργία του δικτύου containers που δημιουργήσαμε χρησμοποιώντας το extension Thunder Client από το περιβάλλον ανάπτυξης του VSCode (Visual Studio Code). Αρχικά θα πραγματοποιήσουμε ένα ΗΤΤP POST αίτημα στον server στο /register route path με κατάλληλo body, έτσι ώστε να εντάξουμε έναν χρήστη στην υπηρεσία. Στη συνέχεια, με το access token που θα λάβει ο συγκεκριμένος χρήστης θα προσπαθήσουμε να αποκτήσουμε πρόσβαση (μέσω HTTP GET αιτήματος) στο /hidden_resource route path. Επειδή ο χρήστης έχει ταυτοποιηθεί και έχει ενεργό access token, θα του επιτραπεί η πρόσβαση στον "hidden" πόρο. Έπειτα, θα προσπαθήσουμε να αποκτήσουμε πρόσβαση (μέσω HTTP GET αιτήματος) στο /hidden_resource route path χρησιμοποιώντας invalid access token και θα δούμε ότι η υπηρεσία δεν θα μας επιτρέψει την πρόσβαση και θα καταγράψει την κίνηση αυτή ως ύποπτη. Έτσι, ο logger θα εμφανίσει στο τερματικό του την ενέργεια αυτή. Τέλος, θα εκτελέσουμε ένα HTTP GET αίτημα στο /hidden_resource route path χωρίς access token. Θα δούμε ότι και σ' αυτή την περίπτωση η υπηρεσία δεν θα μας επιτρέψει την πρόσβαση και θα καταγράψει την κίνηση αυτή ως ύποπτη.

Το παρακάτω gif παρουσιάζει βήμα προς βήμα την εκτέλεση όλων των ενεργειών που αναφέρθηκαν παραπάνω προκειμένου να γίνει έλεγχος της λειτουργίας της υπηρεσίας:

Παρατηρούμε ότι η υπηρεσία μας λειτουργεί όπως επιθυμούσαμε. Όταν εντοπίζεται από το server ύποπτη κίνηση, την καταχωρεί σε ένα αρχείο το οποίο παρακολουθεί ο logger που με τη σειρά του την εμφανίζει στο τερματικό του. Επίσης, τα στοιχεία κάθε νέου χρήστη αποθηκεύονται ορθά στη βάση δεδομένων του αντίστοιχου container.

Contact

Authors:

License

Distributed under the [MIT] License. See LICENSE.md for more details.

About

DockerTutorialGR: 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 data between them.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published