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

Πριν ένα χαρακτηριστικό μπει στην παραγωγή, στις μέρες μας με πολύπλοκους ενορχηστρωτές και CI/CD, υπάρχει πολύς δρόμος από τη δέσμευση έως τις δοκιμές και την παράδοση. Παλαιότερα, μπορούσατε να ανεβάσετε νέα αρχεία μέσω FTP (κανείς δεν το κάνει πια, σωστά;) και η διαδικασία "ανάπτυξης" διαρκούσε δευτερόλεπτα. Τώρα πρέπει να δημιουργήσετε ένα αίτημα συγχώνευσης και να περιμένετε αρκετό χρόνο για να φτάσει η δυνατότητα στους χρήστες.

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

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

Έχουμε καλή εμπειρία στη δημιουργία και υποστήριξη ιστοτόπων πολυμέσων: TASS, Ο Bell, "Νέα Εφημερίδα", Δημοκρατία… Πριν από λίγο καιρό επεκτείναμε το χαρτοφυλάκιό μας κυκλοφορώντας έναν ιστότοπο προϊόντων υπενθύμιση. Και ενώ νέες δυνατότητες προστέθηκαν γρήγορα και τα παλιά σφάλματα διορθώθηκαν, η αργή ανάπτυξη έγινε μεγάλο πρόβλημα.

Αναπτύσσουμε στο GitLab. Συλλέγουμε εικόνες, τις προωθούμε στο GitLab Registry και τις διαθέτουμε στην παραγωγή. Το μεγαλύτερο πράγμα σε αυτή τη λίστα είναι η συναρμολόγηση εικόνων. Για παράδειγμα: χωρίς βελτιστοποίηση, κάθε δημιουργία backend χρειάστηκε 14 λεπτά.

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

Στο τέλος, έγινε σαφές ότι δεν μπορούσαμε πια να ζήσουμε έτσι και καθίσαμε να καταλάβουμε γιατί οι εικόνες αργούσαν τόσο πολύ να συλλεχθούν. Ως αποτέλεσμα, καταφέραμε να μειώσουμε τον χρόνο συναρμολόγησης στα 30 δευτερόλεπτα!

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

Για αυτό το άρθρο, για να μην είμαστε συνδεδεμένοι με το περιβάλλον του Reminder, ας δούμε ένα παράδειγμα συναρμολόγησης μιας άδειας εφαρμογής Angular. Λοιπόν, ας δημιουργήσουμε την εφαρμογή μας:

ng n app

Προσθέστε το PWA σε αυτό (είμαστε προοδευτικοί):

ng add @angular/pwa --project app

Ενώ γίνεται λήψη ενός εκατομμυρίου πακέτων npm, ας δούμε πώς λειτουργεί η εικόνα του docker. Το Docker παρέχει τη δυνατότητα συσκευασίας εφαρμογών και εκτέλεσης σε ένα απομονωμένο περιβάλλον που ονομάζεται κοντέινερ. Χάρη στην απομόνωση, μπορείτε να εκτελέσετε πολλά κοντέινερ ταυτόχρονα σε έναν διακομιστή. Τα κοντέινερ είναι πολύ πιο ελαφριά από τις εικονικές μηχανές επειδή τρέχουν απευθείας στον πυρήνα του συστήματος. Για να τρέξουμε ένα κοντέινερ με την εφαρμογή μας, πρέπει πρώτα να δημιουργήσουμε μια εικόνα στην οποία θα πακετάρουμε όλα όσα είναι απαραίτητα για την εκτέλεση της εφαρμογής μας. Ουσιαστικά, μια εικόνα είναι ένα αντίγραφο του συστήματος αρχείων. Για παράδειγμα, πάρτε το Dockerfile:

FROM node:12.16.2
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build --prod

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

Τι είναι σημαντικό να γνωρίζετε: κάθε επίπεδο Docker μπορεί να αποθηκεύσει προσωρινά. Εάν δεν έχει αλλάξει τίποτα από την τελευταία έκδοση, τότε αντί να εκτελέσει την εντολή, το docker θα πάρει ένα έτοιμο επίπεδο. Δεδομένου ότι η κύρια αύξηση της ταχύτητας κατασκευής θα οφείλεται στη χρήση της κρυφής μνήμης, κατά τη μέτρηση της ταχύτητας κατασκευής θα δώσουμε ιδιαίτερη προσοχή στη δημιουργία μιας εικόνας με μια έτοιμη κρυφή μνήμη. Λοιπόν, βήμα βήμα:

  1. Διαγράφουμε τις εικόνες τοπικά, έτσι ώστε οι προηγούμενες εκτελέσεις να μην επηρεάσουν τη δοκιμή.
    docker rmi $(docker images -q)
  2. Ξεκινάμε την κατασκευή για πρώτη φορά.
    time docker build -t app .
  3. Αλλάζουμε το αρχείο src/index.html - μιμούμαστε τη δουλειά ενός προγραμματιστή.
  4. Εκτελούμε την κατασκευή για δεύτερη φορά.
    time docker build -t app .

Εάν το περιβάλλον για τη δημιουργία εικόνων έχει ρυθμιστεί σωστά (περισσότερα για αυτό παρακάτω), τότε όταν ξεκινήσει η κατασκευή, το Docker θα έχει ήδη μια δέσμη κρυφών μνήμων επί του σκάφους. Το καθήκον μας είναι να μάθουμε πώς να χρησιμοποιούμε την προσωρινή μνήμη, ώστε η κατασκευή να πηγαίνει όσο το δυνατόν γρηγορότερα. Εφόσον υποθέτουμε ότι η εκτέλεση μιας έκδοσης χωρίς προσωρινή μνήμη συμβαίνει μόνο μία φορά—την πρώτη φορά—μπορούμε επομένως να αγνοήσουμε πόσο αργή ήταν αυτή η πρώτη φορά. Στις δοκιμές, η δεύτερη εκτέλεση της κατασκευής είναι σημαντική για εμάς, όταν οι κρυφές μνήμες έχουν ήδη ζεσταθεί και είμαστε έτοιμοι να ψήσουμε το κέικ μας. Ωστόσο, ορισμένες συμβουλές θα επηρεάσουν και την πρώτη κατασκευή.

Ας βάλουμε το Dockerfile που περιγράφεται παραπάνω στον φάκελο του έργου και ας ξεκινήσουμε την κατασκευή. Όλες οι λίστες έχουν συμπυκνωθεί για ευκολία στην ανάγνωση.

$ time docker build -t app .
Sending build context to Docker daemon 409MB
Step 1/5 : FROM node:12.16.2
Status: Downloaded newer image for node:12.16.2
Step 2/5 : WORKDIR /app
Step 3/5 : COPY . .
Step 4/5 : RUN npm ci
added 1357 packages in 22.47s
Step 5/5 : RUN npm run build --prod
Date: 2020-04-16T19:20:09.664Z - Hash: fffa0fddaa3425c55dd3 - Time: 37581ms
Successfully built c8c279335f46
Successfully tagged app:latest

real 5m4.541s
user 0m0.000s
sys 0m0.000s

Αλλάζουμε τα περιεχόμενα του src/index.html και το τρέχουμε για δεύτερη φορά.

$ time docker build -t app .
Sending build context to Docker daemon 409MB
Step 1/5 : FROM node:12.16.2
Step 2/5 : WORKDIR /app
 ---> Using cache
Step 3/5 : COPY . .
Step 4/5 : RUN npm ci
added 1357 packages in 22.47s
Step 5/5 : RUN npm run build --prod
Date: 2020-04-16T19:26:26.587Z - Hash: fffa0fddaa3425c55dd3 - Time: 37902ms
Successfully built 79f335df92d3
Successfully tagged app:latest

real 3m33.262s
user 0m0.000s
sys 0m0.000s

Για να δούμε αν έχουμε την εικόνα, εκτελέστε την εντολή docker images:

REPOSITORY   TAG      IMAGE ID       CREATED              SIZE
app          latest   79f335df92d3   About a minute ago   1.74GB

Πριν από τη δημιουργία, το docker παίρνει όλα τα αρχεία στο τρέχον πλαίσιο και τα στέλνει στον δαίμονά του Sending build context to Docker daemon 409MB. Το περιβάλλον δημιουργίας καθορίζεται ως το τελευταίο όρισμα στην εντολή build. Στην περίπτωσή μας, αυτός είναι ο τρέχων κατάλογος - “.”, - και το Docker σύρει όλα όσα έχουμε σε αυτόν τον φάκελο. 409 MB είναι πολλά: ας σκεφτούμε πώς να το διορθώσουμε.

Μείωση του πλαισίου

Για να μειώσετε το πλαίσιο, υπάρχουν δύο επιλογές. Ή τοποθετήστε όλα τα αρχεία που απαιτούνται για τη συναρμολόγηση σε έναν ξεχωριστό φάκελο και τοποθετήστε το πλαίσιο του docker σε αυτόν τον φάκελο. Αυτό μπορεί να μην είναι πάντα βολικό, επομένως είναι δυνατό να καθοριστούν εξαιρέσεις: τι δεν πρέπει να σύρεται στο πλαίσιο. Για να το κάνετε αυτό, βάλτε το αρχείο .dockerignore στο έργο και υποδείξτε τι δεν χρειάζεται για την κατασκευή:

.git
/node_modules

και εκτελέστε ξανά την κατασκευή:

$ time docker build -t app .
Sending build context to Docker daemon 607.2kB
Step 1/5 : FROM node:12.16.2
Step 2/5 : WORKDIR /app
 ---> Using cache
Step 3/5 : COPY . .
Step 4/5 : RUN npm ci
added 1357 packages in 22.47s
Step 5/5 : RUN npm run build --prod
Date: 2020-04-16T19:33:54.338Z - Hash: fffa0fddaa3425c55dd3 - Time: 37313ms
Successfully built 4942f010792a
Successfully tagged app:latest

real 1m47.763s
user 0m0.000s
sys 0m0.000s

Τα 607.2 KB είναι πολύ καλύτερα από τα 409 MB. Μειώσαμε επίσης το μέγεθος της εικόνας από 1.74 σε 1.38 GB:

REPOSITORY   TAG      IMAGE ID       CREATED         SIZE
app          latest   4942f010792a   3 minutes ago   1.38GB

Ας προσπαθήσουμε να μειώσουμε περαιτέρω το μέγεθος της εικόνας.

Χρησιμοποιούμε Alpine

Ένας άλλος τρόπος για να εξοικονομήσετε μέγεθος εικόνας είναι να χρησιμοποιήσετε μια μικρή γονική εικόνα. Η γονική εικόνα είναι η εικόνα με βάση την οποία προετοιμάζεται η εικόνα μας. Το κάτω στρώμα καθορίζεται από την εντολή FROM στο Dockerfile. Στην περίπτωσή μας, χρησιμοποιούμε μια εικόνα που βασίζεται στο Ubuntu που έχει ήδη εγκαταστήσει nodejs. Και ζυγίζει...

$ docker images -a | grep node
node 12.16.2 406aa3abbc6c 17 minutes ago 916MB

... σχεδόν ένα gigabyte. Μπορείτε να μειώσετε σημαντικά την ένταση χρησιμοποιώντας μια εικόνα που βασίζεται στο Alpine Linux. Το Alpine είναι ένα πολύ μικρό Linux. Η εικόνα docker για nodejs που βασίζονται σε alpine ζυγίζει μόνο 88.5 MB. Ας αντικαταστήσουμε λοιπόν τη ζωηρή εικόνα μας στα σπίτια:

FROM node:12.16.2-alpine3.11
RUN apk --no-cache --update --virtual build-dependencies add 
    python 
    make 
    g++
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build --prod

Έπρεπε να εγκαταστήσουμε κάποια πράγματα που είναι απαραίτητα για την κατασκευή της εφαρμογής. Ναι, το Angular δεν δημιουργεί χωρίς Python ¯(°_o)/¯

Αλλά το μέγεθος της εικόνας μειώθηκε στα 150 MB:

REPOSITORY   TAG      IMAGE ID       CREATED          SIZE
app          latest   aa031edc315a   22 minutes ago   761MB

Ας πάμε ακόμα παραπέρα.

Συναρμολόγηση πολλαπλών σταδίων

Δεν είναι ό,τι είναι στην εικόνα αυτό που χρειαζόμαστε στην παραγωγή.

$ docker run app ls -lah
total 576K
drwxr-xr-x 1 root root 4.0K Apr 16 19:54 .
drwxr-xr-x 1 root root 4.0K Apr 16 20:00 ..
-rwxr-xr-x 1 root root 19 Apr 17 2020 .dockerignore
-rwxr-xr-x 1 root root 246 Apr 17 2020 .editorconfig
-rwxr-xr-x 1 root root 631 Apr 17 2020 .gitignore
-rwxr-xr-x 1 root root 181 Apr 17 2020 Dockerfile
-rwxr-xr-x 1 root root 1020 Apr 17 2020 README.md
-rwxr-xr-x 1 root root 3.6K Apr 17 2020 angular.json
-rwxr-xr-x 1 root root 429 Apr 17 2020 browserslist
drwxr-xr-x 3 root root 4.0K Apr 16 19:54 dist
drwxr-xr-x 3 root root 4.0K Apr 17 2020 e2e
-rwxr-xr-x 1 root root 1015 Apr 17 2020 karma.conf.js
-rwxr-xr-x 1 root root 620 Apr 17 2020 ngsw-config.json
drwxr-xr-x 1 root root 4.0K Apr 16 19:54 node_modules
-rwxr-xr-x 1 root root 494.9K Apr 17 2020 package-lock.json
-rwxr-xr-x 1 root root 1.3K Apr 17 2020 package.json
drwxr-xr-x 5 root root 4.0K Apr 17 2020 src
-rwxr-xr-x 1 root root 210 Apr 17 2020 tsconfig.app.json
-rwxr-xr-x 1 root root 489 Apr 17 2020 tsconfig.json
-rwxr-xr-x 1 root root 270 Apr 17 2020 tsconfig.spec.json
-rwxr-xr-x 1 root root 1.9K Apr 17 2020 tslint.json

Με docker run app ls -lah λανσάραμε ένα κοντέινερ με βάση την εικόνα μας app και εκτέλεσε την εντολή σε αυτό ls -lah, μετά την οποία το κοντέινερ ολοκλήρωσε τις εργασίες του.

Στην παραγωγή χρειαζόμαστε μόνο έναν φάκελο dist. Σε αυτήν την περίπτωση, τα αρχεία με κάποιο τρόπο πρέπει να δίνονται έξω. Μπορείτε να εκτελέσετε κάποιο διακομιστή HTTP σε nodejs. Αλλά θα το κάνουμε πιο εύκολο. Μαντέψτε μια ρωσική λέξη που έχει τέσσερα γράμματα "y". Σωστά! Ynzhynyksy. Ας πάρουμε μια εικόνα με το nginx, βάλουμε ένα φάκελο μέσα dist και μια μικρή διαμόρφωση:

server {
    listen 80 default_server;
    server_name localhost;
    charset utf-8;
    root /app/dist;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Η κατασκευή πολλών σταδίων θα μας βοηθήσει να τα κάνουμε όλα αυτά. Ας αλλάξουμε το Dockerfile μας:

FROM node:12.16.2-alpine3.11 as builder
RUN apk --no-cache --update --virtual build-dependencies add 
    python 
    make 
    g++
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build --prod

FROM nginx:1.17.10-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/static.conf /etc/nginx/conf.d
COPY --from=builder /app/dist/app .

Τώρα έχουμε δύο οδηγίες FROM στο Dockerfile, καθένα από αυτά εκτελεί ένα διαφορετικό βήμα κατασκευής. Καλέσαμε τον πρώτο builder, αλλά ξεκινώντας από το τελευταίο ΑΠΟ, θα ετοιμαστεί η τελική μας εικόνα. Το τελευταίο βήμα είναι να αντιγράψουμε το τεχνούργημα της συναρμολόγησης μας στο προηγούμενο βήμα στην τελική εικόνα με το nginx. Το μέγεθος της εικόνας έχει μειωθεί σημαντικά:

REPOSITORY   TAG      IMAGE ID       CREATED          SIZE
app          latest   2c6c5da07802   29 minutes ago   36MB

Ας τρέξουμε το κοντέινερ με την εικόνα μας και βεβαιωθούμε ότι όλα λειτουργούν:

docker run -p8080:80 app

Χρησιμοποιώντας την επιλογή -p8080:80, προωθήσαμε τη θύρα 8080 στον κεντρικό υπολογιστή μας στη θύρα 80 μέσα στο κοντέινερ όπου εκτελείται το nginx. Ανοιγμα σε πρόγραμμα περιήγησης http://localhost:8080/ και βλέπουμε την εφαρμογή μας. Όλα λειτουργούν!

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

Η μείωση του μεγέθους της εικόνας από 1.74 GB σε 36 MB μειώνει σημαντικά τον χρόνο που απαιτείται για την παράδοση της εφαρμογής σας στην παραγωγή. Ας επιστρέψουμε όμως στην ώρα της συναρμολόγησης.

$ time docker build -t app .
Sending build context to Docker daemon 608.8kB
Step 1/11 : FROM node:12.16.2-alpine3.11 as builder
Step 2/11 : RUN apk --no-cache --update --virtual build-dependencies add python make g++
 ---> Using cache
Step 3/11 : WORKDIR /app
 ---> Using cache
Step 4/11 : COPY . .
Step 5/11 : RUN npm ci
added 1357 packages in 47.338s
Step 6/11 : RUN npm run build --prod
Date: 2020-04-16T21:16:03.899Z - Hash: fffa0fddaa3425c55dd3 - Time: 39948ms
 ---> 27f1479221e4
Step 7/11 : FROM nginx:stable-alpine
Step 8/11 : WORKDIR /app
 ---> Using cache
Step 9/11 : RUN rm /etc/nginx/conf.d/default.conf
 ---> Using cache
Step 10/11 : COPY nginx/static.conf /etc/nginx/conf.d
 ---> Using cache
Step 11/11 : COPY --from=builder /app/dist/app .
Successfully built d201471c91ad
Successfully tagged app:latest

real 2m17.700s
user 0m0.000s
sys 0m0.000s

Αλλαγή της σειράς των επιπέδων

Τα πρώτα τρία μας βήματα αποθηκεύτηκαν στην κρυφή μνήμη (υπόδειξη Using cache). Στο τέταρτο βήμα, αντιγράφονται όλα τα αρχεία έργου και στο πέμπτο βήμα εγκαθίστανται οι εξαρτήσεις RUN npm ci - έως και 47.338 δευτ. Γιατί να επανεγκαθιστάτε τις εξαρτήσεις κάθε φορά, εάν αλλάζουν πολύ σπάνια; Ας καταλάβουμε γιατί δεν είχαν αποθηκευτεί προσωρινά. Το θέμα είναι ότι το Docker θα ελέγχει επίπεδο προς στρώμα για να δει εάν η εντολή και τα αρχεία που σχετίζονται με αυτήν έχουν αλλάξει. Στο τέταρτο βήμα, αντιγράφουμε όλα τα αρχεία του έργου μας, και μεταξύ αυτών, φυσικά, υπάρχουν αλλαγές, οπότε ο Docker όχι μόνο δεν παίρνει αυτό το επίπεδο από την προσωρινή μνήμη, αλλά και όλα τα επόμενα! Ας κάνουμε μερικές μικρές αλλαγές στο Dockerfile.

FROM node:12.16.2-alpine3.11 as builder
RUN apk --no-cache --update --virtual build-dependencies add 
    python 
    make 
    g++
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build --prod

FROM nginx:1.17.10-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/static.conf /etc/nginx/conf.d
COPY --from=builder /app/dist/app .

Αρχικά, το package.json και το package-lock.json αντιγράφονται, στη συνέχεια εγκαθίστανται οι εξαρτήσεις και μόνο μετά από αυτό αντιγράφεται ολόκληρο το έργο. Σαν άποτέλεσμα:

$ time docker build -t app .
Sending build context to Docker daemon 608.8kB
Step 1/12 : FROM node:12.16.2-alpine3.11 as builder
Step 2/12 : RUN apk --no-cache --update --virtual build-dependencies add python make g++
 ---> Using cache
Step 3/12 : WORKDIR /app
 ---> Using cache
Step 4/12 : COPY package*.json ./
 ---> Using cache
Step 5/12 : RUN npm ci
 ---> Using cache
Step 6/12 : COPY . .
Step 7/12 : RUN npm run build --prod
Date: 2020-04-16T21:29:44.770Z - Hash: fffa0fddaa3425c55dd3 - Time: 38287ms
 ---> 1b9448c73558
Step 8/12 : FROM nginx:stable-alpine
Step 9/12 : WORKDIR /app
 ---> Using cache
Step 10/12 : RUN rm /etc/nginx/conf.d/default.conf
 ---> Using cache
Step 11/12 : COPY nginx/static.conf /etc/nginx/conf.d
 ---> Using cache
Step 12/12 : COPY --from=builder /app/dist/app .
Successfully built a44dd7c217c3
Successfully tagged app:latest

real 0m46.497s
user 0m0.000s
sys 0m0.000s

46 δευτερόλεπτα αντί για 3 λεπτά - πολύ καλύτερα! Η σωστή σειρά των επιπέδων είναι σημαντική: πρώτα αντιγράφουμε ό,τι δεν αλλάζει, μετά τι αλλάζει σπάνια και τέλος τι αλλάζει συχνά.

Στη συνέχεια, λίγα λόγια για τη συναρμολόγηση εικόνων σε συστήματα CI/CD.

Χρήση προηγούμενων εικόνων για προσωρινή μνήμη

Εάν χρησιμοποιήσουμε κάποιο είδος λύσης SaaS για την κατασκευή, τότε η τοπική προσωρινή μνήμη Docker μπορεί να είναι καθαρή και φρέσκια. Για να δώσετε στο docker ένα μέρος για να πάρει τα ψημένα στρώματα, δώστε του την προηγούμενη χτισμένη εικόνα.

Ας πάρουμε ένα παράδειγμα δημιουργίας της εφαρμογής μας στο GitHub Actions. Χρησιμοποιούμε αυτήν τη διαμόρφωση

on:
  push:
    branches:
      - master

name: Test docker build

jobs:
  deploy:
    name: Build
    runs-on: ubuntu-latest
    env:
      IMAGE_NAME: docker.pkg.github.com/${{ github.repository }}/app
      IMAGE_TAG: ${{ github.sha }}

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Login to GitHub Packages
      env:
        TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $TOKEN

    - name: Build
      run: |
        docker build 
          -t $IMAGE_NAME:$IMAGE_TAG 
          -t $IMAGE_NAME:latest 
          .

    - name: Push image to GitHub Packages
      run: |
        docker push $IMAGE_NAME:latest
        docker push $IMAGE_NAME:$IMAGE_TAG

    - name: Logout
      run: |
        docker logout docker.pkg.github.com

Η εικόνα συναρμολογείται και προωθείται στα πακέτα GitHub σε δύο λεπτά και 20 δευτερόλεπτα:

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

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

on:
  push:
    branches:
      - master

name: Test docker build

jobs:
  deploy:
    name: Build
    runs-on: ubuntu-latest
    env:
      IMAGE_NAME: docker.pkg.github.com/${{ github.repository }}/app
      IMAGE_TAG: ${{ github.sha }}

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Login to GitHub Packages
      env:
        TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $TOKEN

    - name: Pull latest images
      run: |
        docker pull $IMAGE_NAME:latest || true
        docker pull $IMAGE_NAME-builder-stage:latest || true

    - name: Images list
      run: |
        docker images

    - name: Build
      run: |
        docker build 
          --target builder 
          --cache-from $IMAGE_NAME-builder-stage:latest 
          -t $IMAGE_NAME-builder-stage 
          .
        docker build 
          --cache-from $IMAGE_NAME-builder-stage:latest 
          --cache-from $IMAGE_NAME:latest 
          -t $IMAGE_NAME:$IMAGE_TAG 
          -t $IMAGE_NAME:latest 
          .

    - name: Push image to GitHub Packages
      run: |
        docker push $IMAGE_NAME-builder-stage:latest
        docker push $IMAGE_NAME:latest
        docker push $IMAGE_NAME:$IMAGE_TAG

    - name: Logout
      run: |
        docker logout docker.pkg.github.com

Πρώτα πρέπει να σας πούμε γιατί εκκινούνται δύο εντολές build. Το γεγονός είναι ότι σε μια πολυβάθμια συναρμολόγηση η εικόνα που προκύπτει θα είναι ένα σύνολο στρωμάτων από το τελευταίο στάδιο. Σε αυτήν την περίπτωση, τα επίπεδα από τα προηγούμενα επίπεδα δεν θα συμπεριληφθούν στην εικόνα. Επομένως, όταν χρησιμοποιείτε την τελική εικόνα από μια προηγούμενη έκδοση, το Docker δεν θα μπορεί να βρει έτοιμα επίπεδα για τη δημιουργία της εικόνας με nodejs (στάδιο δημιουργίας). Για να λυθεί αυτό το πρόβλημα, δημιουργείται μια ενδιάμεση εικόνα $IMAGE_NAME-builder-stage και προωθείται στα πακέτα GitHub ώστε να μπορεί να χρησιμοποιηθεί σε μια επόμενη έκδοση ως πηγή προσωρινής μνήμης.

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

Ο συνολικός χρόνος συναρμολόγησης μειώθηκε σε ενάμιση λεπτό. Μισό λεπτό δαπανάται για να τραβήξετε προηγούμενες εικόνες.

Προαπεικόνιση

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

Δημιουργούμε τη δική μας εικόνα nodejs για να δημιουργήσουμε μια εφαρμογή Angular. Δημιουργήστε Dockerfile.node στο έργο

FROM node:12.16.2-alpine3.11
RUN apk --no-cache --update --virtual build-dependencies add 
    python 
    make 
    g++

Συλλέγουμε και προωθούμε μια δημόσια εικόνα στο Docker Hub:

docker build -t exsmund/node-for-angular -f Dockerfile.node .
docker push exsmund/node-for-angular:latest

Τώρα στο κύριο αρχείο μας Docker χρησιμοποιούμε την τελική εικόνα:

FROM exsmund/node-for-angular:latest as builder
...

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

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

Εξετάσαμε διάφορες μεθόδους για την επιτάχυνση της δημιουργίας εικόνων docker. Εάν θέλετε η ανάπτυξη να γίνει γρήγορα, δοκιμάστε να χρησιμοποιήσετε αυτό στο έργο σας:

  • μείωση του πλαισίου·
  • χρήση μικρών εικόνων γονέα.
  • πολυβάθμια συναρμολόγηση?
  • αλλαγή της σειράς των εντολών στο Dockerfile για αποτελεσματική χρήση της κρυφής μνήμης.
  • εγκατάσταση κρυφής μνήμης σε συστήματα CI/CD.
  • προκαταρκτική δημιουργία εικόνων.

Ελπίζω ότι το παράδειγμα θα καταστήσει σαφέστερο τον τρόπο λειτουργίας του Docker και θα μπορέσετε να διαμορφώσετε βέλτιστα την ανάπτυξή σας. Για να παίξετε με τα παραδείγματα από το άρθρο, έχει δημιουργηθεί ένα αποθετήριο https://github.com/devopsprodigy/test-docker-build.

Πηγή: www.habr.com

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