Enne funktsioon jĂ”uab tootmisse, peab see meie keerukate orkestratorite ja CI/CD ajastul lĂ€bima pika tee commitist testide ja tarnimiseni. Varem sai faile FTP kaudu kiiresti ĂŒles laadida (aga keegi ei tee seda enam, eks?), ja âdeploionâ kestis sekundeid. NĂŒĂŒd tuleb luua merge request ja oodata, kuni funktsioon jĂ”uab kasutajateni.
Osa sellest teest on Docker-pildi koostamine. MĂ”nikord kestab koostamine minuteid, mĂ”nikord â kĂŒmneid minuteid, mida on raske normaalseks pidada. Selles artiklis vĂ”tame lihtsa rakenduse, pakime selle pildiks, rakendame mitmeid meetodeid koostamise kiirendamiseks ja vaatame nende meetodite nĂŒansse.

Meil on hea kogemus meedia veebisaitide loomisel ja haldamisel: , , , ⊠Eelmisel ajal tÀiendame oma portfelli, kÀivitades tootmisse veebisaidi . Ja samal ajal kui me kiiresti tÀiendame uusi funktsioone ja parandame vanu vigu, on aeglane deploion muutunud suureks probleemiks.
Deploime GitLabis. Koostame pilte, pushime need GitLabi registrisse ja levitame tootmises. Sellest nimekirjast on aeglasem osa piltide koostamine. NĂ€iteks: ilma optimeerimiseta kestis iga backendi koostamine 14 minutit.
![]()
LÔpuks selgus, et nii ei saa enam elada, ja istusime maha, et aru saada, miks pildid nii kaua koostavad. LÔpuks Ônnestus koostamisaega kÀrpida 30 sekundini!
![]()
KĂ€esolevas artiklis, et mitte seonduda Reminder'i keskkonnaga, vaatame nĂ€idet tĂŒhja rakenduse koostamisest Angularis. Alustame meie rakenduse loomisega:
ng n appLisame sellele PWA (me oleme ju progressiivsed):
ng add @angular/pwa --project appKuni miljoni npm-paketi allalaadimise jooksul vaatame, kuidas docker-pilt töötab. Docker vĂ”imaldab rakendusi pakendada ja kĂ€itada neid isoleeritud keskkonnas, mida nimetatakse konteineriks. Isolatsiooni tĂ”ttu saab samaaegselt ĂŒhel serveril kĂ€itada palju konteineri. Konteinerid on oluliselt kergemad virtuaalsetest masinatest, kuna need töötavad otse sĂŒsteemi tuumast. Meie rakenduse konteineri kĂ€ivitamiseks peame esmalt looma pildi, kuhu pakime kĂ”ik vajalikud komponendid meie rakenduse talitamiseks. Sisuliselt on pilt failisĂŒsteemi koopia. NĂ€iteks vĂ”tame Dockerfile'i:
FROM node:12.16.2
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build --prodDockerfile on komplekt juhiseid; tĂ€itmisel salvestab Docker igaĂŒhe muudatused failisĂŒsteemis ja lisab need eelnevate peale. Iga kĂ€sk loob oma kihi. Valmis image on kokku pandud kihtide kombinatsioon.
Oluline teada: iga kiht suudab Dockeris vahemÀlu salvestada. Kui midagi pole muutunud eelmise ehituse ajal, siis pigem kui kÀsku tÀita, vÔtab docker juba olemasoleva kihi. Kuna peamine kiirusetÔus ehituses toimub vahemÀlu kasutamise kaudu, pöörame ehituse kiirusmÔÔtmistesse tÀhelepanu just valmiskihile. Nii et, sammud on jÀrgmised:
- Kustutame kohalikult pildid, et varasemad kÀivitused ei mÔjutaks testi.
docker rmi $(docker images -q) - KĂ€ivitame ehituse esmakordselt.
time docker build -t app . - Muudame faili src/index.html â jĂ€ljendame programmeerija tööd.
- KĂ€ivitame ehituse teist korda.
time docker build -t app .
Kui pildiehituse keskkond on Ă”igesti seadistatud (mille kohta rÀÀgime natuke allpool), on dockeri kĂ€ivitamisel juba hulk vahemĂ€lusid valmis. Meie ĂŒlesanne on Ă”ppida vahemĂ€lu kasutama nii, et ehitus kulgeks vĂ”imalikult kiiresti. Kuna eeldame, et ilma vahemĂ€luta ehitus kĂ€ivitub ainult ĂŒks kord â kĂ”ige esimene â vĂ”ime ignoreerida, kui aeglane oli see esimene kord. Testides on meie jaoks oluline teine ehitus, kui vahemĂ€lud on juba soojendatud ja oleme valmis meie pirukat kĂŒpsetama. Siiski mĂ”nede nĂ”uannete mĂ”ju avaldub ka esimesel ehitusel.
Paigutame eespool kirjeldatud Dockerfile projekti kausta ja kĂ€ivitame ehituse. KĂ”ik esitatud loetelud on lĂŒhendatud lugemise mugavuse huvides.
$ time docker build -t app .
Saadetakse ehituskontekst Docker daemonile 409MB
Samm 1/5 : FROM node:12.16.2
Oleku: Uus pilt node:12.16.2
Samm 2/5 : WORKDIR /app
Samm 3/5 : COPY . .
Samm 4/5 : RUN npm ci
lisatud 1357 paketid 22.47s
Samm 5/5 : RUN npm run build --prod
KuupÀev: 2020-04-16T19:20:09.664Z - Hash: fffa0fddaa3425c55dd3 - Aeg: 37581ms
Edukas ehitus c8c279335f46
Edukas mÀrgistatud app:latest
reaalne 5m4.541s
kasutaja 0m0.000s
sĂŒsteem 0m0.000sMuudame sisu src/index.html ja kĂ€ivitame teist korda.
$ time docker build -t app .
Saadetakse ehituskontekst Docker daemonile 409MB
Samm 1/5 : FROM node:12.16.2
Samm 2/5 : WORKDIR /app
---> Kasutatakse vahemÀlu
Samm 3/5 : COPY . .
Samm 4/5 : RUN npm ci
lisatud 1357 paketid 22.47s
Samm 5/5 : RUN npm run build --prod
KuupÀev: 2020-04-16T19:26:26.587Z - Hash: fffa0fddaa3425c55dd3 - Aeg: 37902ms
Edukas ehitus 79f335df92d3
Edukas mÀrgistatud app:latest
reaalne 3m33.262s
kasutaja 0m0.000s
sĂŒsteem 0m0.000sKuna tahame nĂ€ha, kas oleme pildi saanud, kĂ€ivitame kĂ€su docker images:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest 79f335df92d3 Umbes minut tagasi 1.74GBEnne dokkeri kogumist vĂ”tab dokker kĂ”ik failid praeguses kontekstis ja saadab need oma daemoni Saadan ehituse konteksti Docker daemonile 409MB. Ehituse konteksti mÀÀratakse build kĂ€su viimase argumendina. Meie puhul on see praegune kataloog â ".", â ja dokker toob kĂ”ik, mis meil selles kaustas on. 409 MB on palju: mĂ”elgem, kuidas seda parandada.
VĂ€hendame konteksti
Konteksti vÀhendamiseks on kaks vÔimalust. Kas panna kÔik ehitamiseks vajalikud failid eraldi kausta ja osutada dokkerile just sellele kaustale. See ei pruugi alati mugav olla, seega on vÔimalus mÀÀrata erandeid: mida ei pea konteksti tooma. Selleks paneme projekti faili .dockerignore ja mÀÀrame, mida ei ole vajalik ehitamiseks:
.git
/node_modulesja kÀivitame ehituse uuesti:
$ time docker build -t app .
Saadan ehituse konteksti Docker daemonile 607.2kB
Step 1/5 : FROM node:12.16.2
Step 2/5 : WORKDIR /app
---> Kasutatakse vahemÀlu
Step 3/5 : COPY . .
Step 4/5 : RUN npm ci
Lisatud 1357 paketti 22.47s jooksul
Step 5/5 : RUN npm run build --prod
KuupÀev: 2020-04-16T19:33:54.338Z - Hash: fffa0fddaa3425c55dd3 - Aeg: 37313ms
Eduka ehituse lÔpetamine 4942f010792a
Eduka sildistamise lÔpetamine app:latest
reaalne 1m47.763s
kasutaja 0m0.000s
sĂŒsteem 0m0.000s607.2 Kb â palju parem kui 409 MB. Lisaks vĂ€hendasime pildi suurust 1.74 GB-lt 1.38 GB-le:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest 4942f010792a 3 minutit tagasi 1.38GBProovime veelgi pildi suurust vÀhendada.
Kasutame Alpine'i
Veel ĂŒks viis pildi suuruse kĂ€rpimiseks on kasutada vĂ€ikest vanemat pilti. Vanem pilt on see pilt, mille pĂ”hjal meie pilt luuakse. Alumine kiht mÀÀratakse kĂ€suga KUST Dockerfile'is. Meie puhul kasutame Ubuntu pĂ”hjal tehtud pilti, kus on juba installitud nodejs. Ja selle suurus on âŠ
$ docker images -a | grep node
node 12.16.2 406aa3abbc6c 17 minutit tagasi 916MB⊠peaaegu gigabait. Oluliselt mahtu vÀhendada saame, kasutades Alpine Linux pÔhjal tehtud pilti. Alpine on vÀga vÀike linux. Docker pilt nodejs jaoks Alpine'i pÔhjal kaalub vaid 88.5 MB. Seega asendame meie suure pildi:
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 --prodMe pidime installima mÔned asjad, mis on vajalikud rakenduse ehitamiseks. Jah, Angular ei ehitu ilma pythonita ¯(°_o)\/¯
Aga pildi suurus langes 150 MB:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest aa031edc315a 22 minutit tagasi 761MBLiigume veelgi kaugemale.
Mitme etapi ehitus
Ei ole kÔike, mis pildis on, meie jaoks tootmises vajalik.
$ 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.jsonEL-i abil docker run app ls -lah meie kÀivitasime konteineri meie pildist app ja tÀitsime selles kÀsu ls -lah, pÀrast mida konteiner lÔpetas oma töö.
Prod-keskkonnas vajame ainult kausta dist. Sellegipoolest peame failid kuidagi vĂ€ljastama. Saame kĂ€ivitada mĂ”ne HTTP-serveri nodejs-is. Kuid teeme lihtsamalt. Arva vene sĂ”na, milles on neli tĂ€hte «Ń». Ăige! Đ«ĐœĐ¶ŃĐœŃĐșŃŃ. VĂ”tame nginx-i pildi, paneme sinna kausta dist ja vĂ€ikese konfi:
server {
listen 80 default_server;
server_name localhost;
charset utf-8;
root /app/dist;
location / {
try_files $uri $uri/ /index.html;
}
}Seda kÔike saab teha multi-stage build abil. Muudame meie Dockerfile'i:
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 .NĂŒĂŒd on meil kaks kĂ€sku KUST Dockerfile'is, millest igaĂŒhel on oma ehitusetapp. Esimese nimega Raspberry Pi 3 jaoks un-def, lts, mp kernelitega, kui pulseaudio on kasutusel, tuleb ĂŒhe helikaardi (kĂ”rvaklapid vĂ”i HDMI) vĂ€lja lĂŒlitada, vastasel juhul vĂ”ib arvuti vĂ€lja lĂŒlitamine kesta kaua ja heli vĂ”ib kaduda pulseaudio tĂ”ttu., kuid alates viimast FROM-ist valmistatakse meie lĂ”plikku pilti. Viimasena kopeerime meie ehitusartefakti eelmisest etapist nginx-i lĂ”plikku pilti. Pildi suurus on oluliselt vĂ€henenud:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest 2c6c5da07802 29 minutes ago 36MBKÀivitame konteineri meie pildiga ja veendume, et kÔik töötab:
docker run -p8080:80 appValiku -p8080:80 kaudu suunamine viib meie hostmasinalt portaali 8080 konteineri 80-le, kus nginx töötab. Avame brauseris ja nÀeme meie rakendust. KÔik töötab!

Pildi suuruse vĂ€hendamine 1,74 GB-lt 36 MB-le lĂŒhendab oluliselt teie rakenduse toimetamise aega. Kuid naaseme ehitusaega.
$ 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.000sMuudame kihtide jÀrjekorda
Esimesed kolm sammu on meil vahemĂ€lul (vihje Using cache). Neljandas etapis kopeeritakse kĂ”ik projektifailid ja viiendas etapis installitakse sĂ”ltuvused RUN npm ci â kokku 47.338s. Miks installida sĂ”ltuvusi iga kord uuesti, kui need harva muutuvad? Vaatame, miks need ei ole vahemĂ€lusse salvestunud. Asi on selles, et Docker kontrollib kihtide kaupa, kas kĂ€sk ja sellega seotud failid on muutunud. Neljandas sammus kopeerime kĂ”ik meie projekti failid, ja nende seas on loomulikult muudatusi, seega Docker ei kasuta mitte ainult seda kihti vahemĂ€lust, vaid ka kĂ”iki jĂ€rgnevaid! Teeme Dockerfile'is vĂ€ikeseid muudatusi.
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 .Esiteks kopeeritakse package.json ja package-lock.json, seejÀrel installitakse sÔltuvused ja alles siis kopeeritakse terve projekt. Tulemuseks:
$ time docker build -t app .
Saatmine ehituse konteksti Docker daemonile 608.8kB
1/12 etapp: FROM node:12.16.2-alpine3.11 as builder
2/12 etapp: RUN apk --no-cache --update --virtual build-dependencies add python make g++
---> Kasutatakse vahemÀlu
3/12 etapp: WORKDIR /app
---> Kasutatakse vahemÀlu
4/12 etapp: COPY package*.json ./
---> Kasutatakse vahemÀlu
5/12 etapp: RUN npm ci
---> Kasutatakse vahemÀlu
6/12 etapp: COPY . .
7/12 etapp: RUN npm run build --prod
KuupÀev: 2020-04-16T21:29:44.770Z - Hash: fffa0fddaa3425c55dd3 - Aeg: 38287ms
---> 1b9448c73558
8/12 etapp: FROM nginx:stable-alpine
9/12 etapp: WORKDIR /app
---> Kasutatakse vahemÀlu
10/12 etapp: RUN rm /etc/nginx/conf.d/default.conf
---> Kasutatakse vahemÀlu
11/12 etapp: COPY nginx/static.conf /etc/nginx/conf.d
---> Kasutatakse vahemÀlu
12/12 etapp: COPY --from=builder /app/dist/app .
Ehitamine Ônnestus a44dd7c217c3
Ehitamine mÀrgitud: app:latest
reaalne 0m46.497s
kasutaja 0m0.000s
sĂŒsteem 0m0.000s46 sekundit, mitte 3 minutit â oluliselt parem! Oluline on kihtide Ă”ige jĂ€rjekord: esmalt kopeerime selle, mis ei muutu, seejĂ€rel selle, mis harva muutub, ja lĂ”puks â selle, mis tihti.
JĂ€rgmine paar sĂ”na piltide ehitamisest CI/CD sĂŒsteemides.
Eelnevate piltide kasutamine vahemÀluna
Kui kasutame mĂ”nda SaaS-lahendust kogumise jaoks, vĂ”ib kohalik Docker vahemĂ€lu olla tĂŒhi ja vĂ€rske. Et Dockeril oleks kustki vĂ”tta kĂŒpsetatud kihte, andke talle eelnevalt koostatud pilt.
Vaadakem nÀiteks meie rakenduse ehitamist GitHub Actions'is. Kasutame sellist konfi
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.comPildi loomine ja saatmine GitHub Packages'i kestab kaks minutit ja 20 sekundit:

NĂŒĂŒd muudame ehituse nii, et kasutatakse eelmisel korral loodud piltide pĂ”hjal cache'i:
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.comEsiteks tuleb rÀÀkida, miks kÀivitatakse kaks kÀsku build. Asi on selles, et mitmestastilise ehituse tulemusena on lÔpp-produkt viimasest etapist koosnev kihistikum. Samal ajal ei pÀÀse eelmistest kihtidest loodud kihid pildisse. SeetÔttu, kui kasutada viimase ehituse lÔpp-pilti, ei suuda Docker leida valmis kihte Node.js pildi (ehituse etapp) jaoks. Selle probleemi lahendamiseks luuakse vahepealne pilt $IMAGE_NAME-builder-stage ja saadetakse GitHub Packages'isse, et saaks seda jÀrgmises ehituses kasutada cache'i allikana.

KokkuvĂ”ttes on ehitamise aeg lĂŒhenenud ĂŒhele ja poolele minutile. Pool minutit kulub eelnevate piltide allalaadimisele.
Eelneva pildi loomine
Veel, kuidas lahendada puhta docker-kihi probleemi, on osa kihtidest viia teise Dockerfile'i, koguda see eraldi, pushida see Container Registry'sse ja kasutada seda vanemana.
Loome oma nodejs pildi Angular-rakenduse ehitamiseks. Loome projektis Dockerfile.node.
FROM node:12.16.2-alpine3.11
RUN apk --no-cache --update --virtual ehitus-sÔltuvused lisada
python
make
g++Kogume ja pushime avaliku pildi Docker Hub'i:
docker build -t exsmund/node-for-angular -f Dockerfile.node .
docker push exsmund/node-for-angular:latestNĂŒĂŒd kasutame meie pĂ”hikanalis valmis pilti:
FROM exsmund/node-for-angular:latest as builder
...Meie nÀites ei vÀhenenud ehitusaeg, kuid eelnevalt loodud pildid vÔivad olla kasulikud, kui teil on palju projekte ja igas neist tuleb paigaldada sama sÔltuvus.

Oleme vaadanud mitmeid meetodeid docker-piltide ehituse kiirusel. Kui soovite, et juurutamine oleks kiire, proovige oma projektis rakendada:
- konteksti vÀhendamine;
- vÀikeste vanemate piltide kasutamine;
- mitmeastmelist ehitamist;
- Dockerfile'i kÀskude jÀrjekorra muutmine, et tÔhusalt kasutada vahemÀlu;
- vahemĂ€lu seadistamine CI/CD sĂŒsteemides;
- eelnevalt loodud piltide tegemine.
Loodetavasti selgub nÀitest, kuidas Docker töötab, ja suudate oma juurutuse optimaalselt seadistada. Artikli nÀidistega mÀngimiseks on loodud hoidla. .
Allikas: habr.com
