Функция өндүрүшкө кире электе, азыркы татаал оркестрлер жана CI/CD күндөрү, сыноодон жана жеткирүүгө чейин көп жол бар. Мурда, сиз жаңы файлдарды FTP аркылуу жүктөй алчусуз (мындан ары муну эч ким жасабайт, туурабы?) жана "орнизациялоо" процесси бир нече секундага созулду. Эми сиз бириктирүү өтүнүчүн түзүп, функция колдонуучуларга жетүү үчүн көпкө күтүшүңүз керек.
Бул жолдун бир бөлүгү Docker сүрөтүн куруу болуп саналат. Кээде жыйын бир нече мүнөткө, кээде ондогон мүнөткө созулат, муну нормалдуу деп айтуу кыйын. Бул макалада биз жөнөкөй тиркемени алып, аны сүрөткө топтоп, курууну тездетүү үчүн бир нече ыкмаларды колдонобуз жана бул ыкмалардын кантип иштээрин карап чыгабыз.
Бизде медиа веб-сайттарды түзүү жана колдоо боюнча жакшы тажрыйба бар:
Биз GitLabга жайгаштырабыз. Биз сүрөттөрдү чогултабыз, аларды GitLab реестрине түртүп, өндүрүшкө чыгарабыз. Бул тизмедеги эң узун нерсе - сүрөттөрдү чогултуу. Мисалы: оптималдаштыруусуз, ар бир арткы түзүлүш 14 мүнөттү алды.
Акырында мындан ары минтип жашай албасыбыз айкын болуп, сүрөттөрдү чогултуу эмне үчүн мынчалык көпкө созулуп жатканын түшүнүү үчүн отурдук. Натыйжада монтаждоо убактысын 30 секундага чейин кыскартууга жетиштик!
Бул макала үчүн, Reminder чөйрөсүнө байланбоо үчүн, бош Angular тиркемесин чогултуунун мисалын карап көрөлү. Ошентип, келгиле, биздин колдонмону түзөлү:
ng n app
Ага PWA кошуңуз (биз прогрессивдүүбүз):
ng add @angular/pwa --project app
Миллион npm пакеттери жүктөлүп жатканда, келгиле, докердин сүрөтү кантип иштээрин аныктап көрөлү. Docker колдонмолорду пакеттөө жана аларды контейнер деп аталган обочолонгон чөйрөдө иштетүү мүмкүнчүлүгүн берет. Изоляциянын аркасында бир серверде бир эле учурда көптөгөн контейнерлерди иштете аласыз. Контейнерлер виртуалдык машиналарга караганда бир топ жеңил, анткени алар түз системанын өзөгүндө иштейт. Колдонмобуз менен контейнерди иштетүү үчүн, биз алгач колдонмобуздун иштеши үчүн зарыл болгон нерселердин баарын топтой турган сүрөттү түзүшүбүз керек. Негизи, сүрөт файл тутумунун көчүрмөсү. Мисалы, Dockerfile файлын алыңыз:
FROM node:12.16.2
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build --prod
Dockerfile – бул нускамалардын жыйындысы; Алардын ар бирин аткаруу менен, Docker файл тутумуна өзгөртүүлөрдү сактап, аларды мурункуларына каптайт. Ар бир команда өзүнүн катмарын түзөт. Ал эми даяр сүрөттөлүш бириктирилген катмарлар болуп саналат.
Эмнени билүү маанилүү: ар бир Docker катмары кэштей алат. Эгерде акыркы куруудан бери эч нерсе өзгөрбөсө, анда буйрукту аткаруунун ордуна, докер даяр катмарды алат. Куруу ылдамдыгынын негизги өсүшү кэшти колдонуу менен шартталгандыктан, куруу ылдамдыгын өлчөгөндө биз даяр кэш менен сүрөттү курууга өзгөчө көңүл бурабыз. Ошентип, этап-этабы менен:
- Мурунку иштетүүлөр сыноого таасирин тийгизбеши үчүн сүрөттөрдү жергиликтүү түрдө жок кылабыз.
docker rmi $(docker images -q)
- Биз курулушту биринчи жолу ишке киргизип жатабыз.
time docker build -t app .
- Биз src/index.html файлын өзгөртөбүз - биз программисттин ишин туурайбыз.
- Биз курулушту экинчи жолу жүргүзүп жатабыз.
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
Курардан мурун докер учурдагы контексттеги бардык файлдарды алып, аларды өзүнүн демонуна жөнөтөт Sending build context to Docker daemon 409MB
. Куруу контексти куруу буйругунун акыркы аргументи катары көрсөтүлөт. Биздин учурда, бул учурдагы каталог - ".", - жана Docker бул папкадагы нерселердин бардыгын сүйрөп барат. 409 МБ көп: келгиле, аны кантип оңдоону ойлонуп көрөлү.
Контекстти кыскартуу
Контекстти азайтуу үчүн эки вариант бар. Же чогултуу үчүн зарыл болгон бардык файлдарды өзүнчө папкага салып, докер контекстти ушул папкага багыттаңыз. Бул дайыма эле ыңгайлуу боло бербеши мүмкүн, андыктан өзгөчө учурларды көрсөтүүгө болот: эмнени контекстке сүйрөп кирбеш керек. Бул үчүн, .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 КБ 409 МБга караганда алда канча жакшы. Биз ошондой эле сүрөттүн көлөмүн 1.74 ГБдан 1.38 ГБ чейин кыскарттык:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest 4942f010792a 3 minutes ago 1.38GB
Сүрөттүн көлөмүн дагы кичирейтүүгө аракет кылалы.
Биз Alpine колдонобуз
Сүрөт өлчөмүн сактоонун дагы бир жолу кичинекей ата-эне сүрөтүн колдонуу. Ата-эненин образы – бул биздин образыбыз даярдалган образ. Төмөнкү катмар буйрук менен аныкталат FROM
Dockerfileде. Биздин учурда, биз мурунтан эле nodejs орнотулган Ubuntu негизиндеги сүрөттү колдонуп жатабыз. Ал эми салмагы ...
$ docker images -a | grep node
node 12.16.2 406aa3abbc6c 17 minutes ago 916MB
... дээрлик бир гигабайт. Alpine Linux негизиндеги сүрөттү колдонуу менен үндү бир топ азайта аласыз. Alpine абдан кичинекей Linux болуп саналат. Alpine негизделген nodejs үчүн докер сүрөтүнүн салмагы болгону 88.5 МБ. Келгиле, үйлөрдөгү жандуу образыбызды алмаштыралы:
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 МБ чейин төмөндөдү:
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
. Бул учурда, файлдар кандайдыр бир жол менен сырттан берилиши керек. Сиз nodejs боюнча кээ бир HTTP серверин иштете аласыз. Бирок биз муну жеңилдетебиз. Төрт "у" тамгасынан турган орусча сөздү тапкыла. Туура! Ынжыныксы. Келгиле, nginx менен сүрөт тарталы, ага папка сал dist
жана кичинекей конфигурация:
server {
listen 80 default_server;
server_name localhost;
charset utf-8;
root /app/dist;
location / {
try_files $uri $uri/ /index.html;
}
}
Көп баскычтуу курулуш бизге мунун баарын жасоого жардам берет. Докер файлыбызды өзгөртөлү:
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
, бирок акыркы FROMдон баштап акыркы сүрөтүбүз даярдалат. Акыркы кадам - мурунку кадамдагы биздин жыйындын артефактын nginx менен акыркы сүрөткө көчүрүү. Сүрөттүн көлөмү бир топ кыскарды:
REPOSITORY TAG IMAGE ID CREATED SIZE
app latest 2c6c5da07802 29 minutes ago 36MB
Келгиле, контейнерди сүрөтүбүз менен иштетип, бардыгынын иштешин текшерели:
docker run -p8080:80 app
-p8080:80 опциясын колдонуп, биз хост машинабыздагы 8080 портун nginx иштеген контейнердин ичиндеги 80 портуна жөнөттүк. Браузерде ачуу
Сүрөттүн көлөмүн 1.74 ГБдан 36 МБга чейин кыскартуу колдонмоңузду өндүрүшкө жеткирүүгө кеткен убакытты бир топ кыскартат. Бирок чогулуш убактысына кайрылалы.
$ 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 кэши таза жана жаңы болушу мүмкүн. Докерге бышырылган катмарларды алуу үчүн орун берүү үчүн, ага мурунку курулган сүрөттү бериңиз.
Келгиле, GitHub Аракеттеринде биздин тиркемени куруунун мисалын алалы. Биз бул конфигурацияны колдонобуз
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
Сүрөт эки мүнөт 20 секундда GitHub пакеттерине чогултулуп, түртүлөт:
Эми мурунку курулган сүрөттөрдүн негизинде кэш колдонула тургандай кылып түзүүнү өзгөртөлү:
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 кэшинин көйгөйүн чечүүнүн дагы бир жолу - кээ бир катмарларды башка Dockerfileге жылдыруу, аны өзүнчө куруу, аны Контейнер реестрине түртүү жана аны ата-эне катары колдонуу.
Angular тиркемесин түзүү үчүн биз өзүбүздүн nodejs сүрөтүбүздү түзөбүз. Долбоордо 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
Эми биздин негизги Dockerfileде биз даяр сүрөттү колдонобуз:
FROM exsmund/node-for-angular:latest as builder
...
Биздин мисалда, куруу убактысы азайган жок, бирок сизде көптөгөн долбоорлор болсо жана алардын ар бирине бирдей көз карандылыктарды орнотуу керек болсо, алдын ала курулган сүрөттөр пайдалуу болушу мүмкүн.
Биз докер сүрөттөрүн түзүүнү тездетүүнүн бир нече ыкмаларын карап чыктык. Эгер жайылтуунун тез болушун кааласаңыз, муну долбооруңузда колдонуп көрүңүз:
- контекстти кыскартуу;
- кичинекей ата-энелер сүрөттөрүн колдонуу;
- көп баскычтуу чогултуу;
- кэшти эффективдүү пайдалануу үчүн Dockerfileдеги нускамалардын тартибин өзгөртүү;
- CI/CD системаларында кэш орнотуу;
- сүрөттөрдү алдын ала түзүү.
Мисал Docker кантип иштээрин айкыныраак көрсөтөт деп үмүттөнөм жана сиз жайгаштырууну оптималдуу конфигурациялай аласыз. Макаладагы мисалдар менен ойноо үчүн репозиторий түзүлгөн
Source: www.habr.com