Σκεφτείτε προσεκτικά πριν χρησιμοποιήσετε το Docker-in-Docker για CI ή δοκιμαστικό περιβάλλον

Σκεφτείτε προσεκτικά πριν χρησιμοποιήσετε το Docker-in-Docker για CI ή δοκιμαστικό περιβάλλον

Το Docker-in-Docker είναι ένα εικονικοποιημένο περιβάλλον δαίμονα Docker που εκτελείται μέσα στο ίδιο το κοντέινερ για τη δημιουργία εικόνων κοντέινερ. Ο κύριος σκοπός της δημιουργίας του Docker-in-Docker ήταν να βοηθήσει στην ανάπτυξη του ίδιου του Docker. Πολλοί το χρησιμοποιούν για να τρέξουν το Jenkins CI. Αυτό φαίνεται φυσιολογικό στην αρχή, αλλά στη συνέχεια προκύπτουν προβλήματα που μπορούν να αποφευχθούν με την εγκατάσταση του Docker σε ένα κοντέινερ Jenkins CI. Αυτό το άρθρο σας λέει πώς να το κάνετε αυτό. Εάν ενδιαφέρεστε για την τελική λύση χωρίς λεπτομέρειες, απλώς διαβάστε την τελευταία ενότητα του άρθρου, «Επίλυση του προβλήματος».

Σκεφτείτε προσεκτικά πριν χρησιμοποιήσετε το Docker-in-Docker για CI ή δοκιμαστικό περιβάλλον

Docker-in-Docker: "Καλό"

Πριν από περισσότερα από δύο χρόνια έβαλα το Docker σημαία –προνόμιο και έγραψε πρώτη έκδοση του dind. Ο στόχος ήταν να βοηθηθεί η βασική ομάδα να αναπτύξει το Docker πιο γρήγορα. Πριν από το Docker-in-Docker, ο τυπικός κύκλος ανάπτυξης έμοιαζε ως εξής:

  • hackity hack?
  • χτίζω;
  • διακοπή ενός τρέχοντος Docker daemon.
  • λανσάροντας έναν νέο δαίμονα Docker.
  • δοκιμές.
  • επαναλάβετε τον κύκλο.

Εάν θέλατε να φτιάξετε μια όμορφη, αναπαραγώγιμη διάταξη (δηλαδή σε ένα δοχείο), τότε έγινε πιο περίπλοκο:

  • hackity hack?
  • βεβαιωθείτε ότι εκτελείται μια λειτουργική έκδοση του Docker.
  • Δημιουργήστε νέο Docker με το παλιό Docker.
  • σταματήστε τον δαίμονα Docker?
  • ξεκινήστε έναν νέο δαίμονα Docker.
  • δοκιμή;
  • σταματήστε τον νέο δαίμονα Docker.
  • επαναλαμβάνω.

Με την εμφάνιση του Docker-in-Docker, η διαδικασία έχει γίνει πιο απλή:

  • hackity hack?
  • συναρμολόγηση + εκκίνηση σε ένα στάδιο.
  • επαναλάβετε τον κύκλο.

Δεν είναι πολύ καλύτερα έτσι;

Σκεφτείτε προσεκτικά πριν χρησιμοποιήσετε το Docker-in-Docker για CI ή δοκιμαστικό περιβάλλον

Docker-in-Docker: "Bad"

Ωστόσο, σε αντίθεση με τη δημοφιλή πεποίθηση, το Docker-in-Docker δεν είναι 100% αστέρια, πόνυ και μονόκεροι. Αυτό που εννοώ είναι ότι υπάρχουν πολλά ζητήματα που πρέπει να γνωρίζει ένας προγραμματιστής.

Ένα από αυτά αφορά τα LSM (μονάδες ασφαλείας Linux) όπως το AppArmor και το SELinux: όταν εκτελείται ένα κοντέινερ, το "εσωτερικό Docker" μπορεί να προσπαθήσει να εφαρμόσει προφίλ ασφαλείας που θα φέρουν σύγκρουση ή θα μπερδέψουν το "εξωτερικό Docker". Αυτό είναι το πιο δύσκολο πρόβλημα που πρέπει να λυθεί όταν προσπαθείτε να συγχωνεύσετε την αρχική υλοποίηση της προνομιακής σημαίας. Οι αλλαγές μου λειτούργησαν και όλες οι δοκιμές θα περνούσαν στη μηχανή Debian και στα δοκιμαστικά VM του Ubuntu, αλλά θα κολλούσαν και θα έκαιγαν στη μηχανή του Michael Crosby (είχε το Fedora όπως θυμάμαι). Δεν μπορώ να θυμηθώ την ακριβή αιτία του προβλήματος, αλλά μπορεί να οφείλεται στο ότι ο Mike είναι ένας σοφός τύπος που δουλεύει με το SELINUX=enforce (χρησιμοποίησα το AppArmor) και οι αλλαγές μου δεν έλαβαν υπόψη τα προφίλ SELinux.

Docker-in-Docker: "Evil"

Το δεύτερο πρόβλημα είναι με τα προγράμματα οδήγησης αποθήκευσης Docker. Όταν εκτελείτε το Docker-in-Docker, το εξωτερικό Docker εκτελείται πάνω από ένα κανονικό σύστημα αρχείων (EXT4, BTRFS ή οτιδήποτε άλλο έχετε) και το εσωτερικό Docker εκτελείται πάνω από ένα σύστημα αντιγραφής σε εγγραφή (AUFS, BTRFS, Device Mapper , κ.λπ.). , ανάλογα με το τι έχει ρυθμιστεί να χρησιμοποιεί εξωτερικό Docker). Αυτό δημιουργεί πολλούς συνδυασμούς που δεν θα λειτουργήσουν. Για παράδειγμα, δεν θα μπορείτε να εκτελέσετε το AUFS πάνω από το AUFS.

Εάν εκτελείτε το BTRFS πάνω από το BTRFS, θα πρέπει να λειτουργεί στην αρχή, αλλά όταν υπάρχουν ένθετοι υποτόμοι, η διαγραφή του γονικού υποτόμου θα αποτύχει. Η λειτουργική μονάδα Device Mapper δεν έχει χώρο ονομάτων, επομένως, εάν πολλές παρουσίες Docker την εκτελούν στον ίδιο υπολογιστή, θα μπορούν όλες να δουν (και να επηρεάσουν) τις εικόνες μεταξύ τους και στις συσκευές δημιουργίας αντιγράφων ασφαλείας κοντέινερ. Αυτό είναι κακό.

Υπάρχουν λύσεις για την επίλυση πολλών από αυτά τα προβλήματα. Για παράδειγμα, εάν θέλετε να χρησιμοποιήσετε το AUFS στο εσωτερικό Docker, απλώς μετατρέψτε τον φάκελο /var/lib/docker σε τόμο και θα είστε εντάξει. Το Docker έχει προσθέσει ορισμένους χώρους ονομάτων βάσης στα ονόματα στόχων του Device Mapper, έτσι ώστε, εάν εκτελούνται πολλές κλήσεις Docker στον ίδιο υπολογιστή, να μην πατάνε η μία την άλλη.

Ωστόσο, μια τέτοια ρύθμιση δεν είναι καθόλου απλή, όπως φαίνεται από αυτά άρθρα στο αποθετήριο dind στο GitHub.

Docker-in-Docker: Γίνεται χειρότερο

Τι γίνεται με την κρυφή μνήμη κατασκευής; Αυτό μπορεί επίσης να είναι αρκετά δύσκολο. Οι άνθρωποι συχνά με ρωτούν "εάν εκτελώ το Docker-in-Docker, πώς μπορώ να χρησιμοποιήσω εικόνες που φιλοξενούνται στον κεντρικό μου υπολογιστή αντί να ανασύρω τα πάντα στο εσωτερικό μου Docker";

Μερικοί επιχειρηματίες προσπάθησαν να συνδέσουν το /var/lib/docker από τον κεντρικό υπολογιστή σε ένα κοντέινερ Docker-in-Docker. Μερικές φορές μοιράζονται το /var/lib/docker με πολλά κοντέινερ.

Σκεφτείτε προσεκτικά πριν χρησιμοποιήσετε το Docker-in-Docker για CI ή δοκιμαστικό περιβάλλον
Θέλετε να καταστρέψετε τα δεδομένα σας; Γιατί αυτό ακριβώς θα βλάψει τα δεδομένα σας!

Ο δαίμονας Docker σχεδιάστηκε σαφώς για να έχει αποκλειστική πρόσβαση στο /var/lib/docker. Τίποτα άλλο δεν πρέπει να "αγγίξει, να σπρώξει ή να προωθήσει" αρχεία Docker που βρίσκονται σε αυτόν τον φάκελο.

Γιατί συμβαίνει αυτό; Επειδή αυτό είναι το αποτέλεσμα ενός από τα πιο δύσκολα μαθήματα που αντλήθηκαν κατά την ανάπτυξη του dotCloud. Η μηχανή κοντέινερ dotCloud λειτουργούσε έχοντας πολλαπλές διεργασίες που είχαν πρόσβαση στο /var/lib/dotcloud ταυτόχρονα. Πονηρά κόλπα όπως η αντικατάσταση ατομικού αρχείου (αντί για επιτόπια επεξεργασία), η δημιουργία κώδικα με συμβουλευτικές και υποχρεωτικές κλειδαριές και άλλα πειράματα με ασφαλή συστήματα όπως το SQLite και το BDB δεν λειτουργούσαν πάντα. Όταν επανασχεδιάζαμε τη μηχανή εμπορευματοκιβωτίων μας, η οποία τελικά έγινε Docker, μία από τις μεγάλες αποφάσεις σχεδιασμού ήταν να ενοποιήσουμε όλες τις λειτουργίες εμπορευματοκιβωτίων κάτω από έναν ενιαίο δαίμονα για να εξαλείψουμε όλες τις ανοησίες του συγχρονισμού.

Μην με παρεξηγείτε: είναι απολύτως δυνατό να φτιάξετε κάτι καλό, αξιόπιστο και γρήγορο που να περιλαμβάνει πολλαπλές διαδικασίες και σύγχρονο παράλληλο έλεγχο. Αλλά πιστεύουμε ότι είναι απλούστερο και πιο εύκολο να γράψετε και να διατηρήσετε κώδικα χρησιμοποιώντας το Docker ως το μοναδικό πρόγραμμα αναπαραγωγής.

Αυτό σημαίνει ότι εάν μοιράζεστε τον κατάλογο /var/lib/docker μεταξύ πολλαπλών παρουσιών Docker, θα έχετε προβλήματα. Φυσικά, αυτό μπορεί να λειτουργήσει, ειδικά στα αρχικά στάδια της δοκιμής. «Άκου, μαμά, μπορώ να τρέξω το ubuntu ως docker!» Αλλά δοκιμάστε κάτι πιο περίπλοκο, όπως να τραβήξετε την ίδια εικόνα από δύο διαφορετικές περιπτώσεις, και θα δείτε τον κόσμο να καίγεται.

Αυτό σημαίνει ότι εάν το σύστημά σας CI πραγματοποιεί εκδόσεις και ανακατασκευές, κάθε φορά που επανεκκινείτε το κοντέινερ Docker-in-Docker, κινδυνεύετε να ρίξετε ένα πυρηνικό όπλο στην κρυφή μνήμη του. Αυτό δεν είναι καθόλου ωραίο!

Το διάλυμα

Ας κάνουμε ένα βήμα πίσω. Χρειάζεστε πραγματικά το Docker-in-Docker ή θέλετε απλώς να μπορείτε να εκτελέσετε το Docker και να δημιουργήσετε και να εκτελέσετε κοντέινερ και εικόνες από το σύστημά σας CI ενώ αυτό το ίδιο το σύστημα CI βρίσκεται σε ένα κοντέινερ;

Βάζω στοίχημα ότι οι περισσότεροι άνθρωποι θέλουν την τελευταία επιλογή, που σημαίνει ότι θέλουν ένα σύστημα CI όπως το Jenkins να μπορεί να λειτουργεί κοντέινερ. Και ο ευκολότερος τρόπος για να το κάνετε αυτό είναι απλώς να εισαγάγετε μια υποδοχή Docker στο κοντέινερ CI και να τη συσχετίσετε με τη σημαία -v.

Με απλά λόγια, όταν τρέχετε το κοντέινερ CI (Jenkins ή άλλο), αντί να χακάρετε κάτι μαζί με το Docker-in-Docker, ξεκινήστε το με τη γραμμή:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

Αυτό το κοντέινερ θα έχει πλέον πρόσβαση στην υποδοχή Docker και επομένως θα μπορεί να εκτελεί κοντέινερ. Μόνο που αντί να τρέχει κοντέινερ "παιδικό", θα εκτοξεύει κοντέινερ "αδερφού".

Δοκιμάστε αυτό χρησιμοποιώντας την επίσημη εικόνα docker (η οποία περιέχει το δυαδικό Docker):

docker run -v /var/run/docker.sock:/var/run/docker.sock 
           -ti docker

Μοιάζει και λειτουργεί με το Docker-in-Docker, αλλά δεν είναι Docker-in-Docker: όταν αυτό το κοντέινερ δημιουργεί επιπλέον κοντέινερ, θα δημιουργηθούν στο Docker ανώτατου επιπέδου. Δεν θα αντιμετωπίσετε τις παρενέργειες της ένθεσης και η κρυφή μνήμη συναρμολόγησης θα μοιράζεται σε πολλές κλήσεις.

Σημείωση: Προηγούμενες εκδόσεις αυτού του άρθρου συνιστούσαν τη σύνδεση του δυαδικού Docker από τον κεντρικό υπολογιστή στο κοντέινερ. Αυτό έχει πλέον καταστεί αναξιόπιστο καθώς η μηχανή Docker δεν καλύπτει πλέον στατικές ή σχεδόν στατικές βιβλιοθήκες.

Έτσι, εάν θέλετε να χρησιμοποιήσετε το Docker από την Jenkins CI, έχετε 2 επιλογές:
εγκατάσταση του Docker CLI χρησιμοποιώντας το βασικό σύστημα συσκευασίας εικόνων (δηλαδή, εάν η εικόνα σας βασίζεται στο Debian, χρησιμοποιήστε πακέτα .deb), χρησιμοποιώντας το Docker API.

Μερικές διαφημίσεις 🙂

Σας ευχαριστούμε που μείνατε μαζί μας. Σας αρέσουν τα άρθρα μας; Θέλετε να δείτε πιο ενδιαφέρον περιεχόμενο; Υποστηρίξτε μας κάνοντας μια παραγγελία ή προτείνοντας σε φίλους, cloud VPS για προγραμματιστές από 4.99 $, ένα μοναδικό ανάλογο διακομιστών εισαγωγικού επιπέδου, το οποίο εφευρέθηκε από εμάς για εσάς: Όλη η αλήθεια για το VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps από 19 $ ή πώς να μοιραστείτε έναν διακομιστή; (διατίθεται με RAID1 και RAID10, έως 24 πυρήνες και έως 40 GB DDR4).

Το Dell R730xd 2 φορές φθηνότερο στο κέντρο δεδομένων Equinix Tier IV στο Άμστερνταμ; Μόνο εδώ 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 Τηλεόραση από 199$ στην Ολλανδία! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - από 99$! Διαβάστε σχετικά Πώς να χτίσετε την υποδομή Corp. κατηγορίας με τη χρήση διακομιστών Dell R730xd E5-2650 v4 αξίας 9000 ευρώ για μια δεκάρα;

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο