Багатоступенева збірка Docker-образу
Розробка ПО — складний процес, результатом якого є працюючий «в миру» продукт/сервіс. Давайте познайомимося з підходом, що дозволяє спростити життєвий цикл розробки.
Реалізація
Починаючи з версії 17.05, в докері з'явилися багатоступінчасті білди. Багатоступінчасті складання корисні для всіх, хто намагається оптимізувати Docker-файли і образи, зберігаючи їх легкими для читання та обслуговування. До появи цієї фічі застосовували підхід під назвою «Builder Pattern». Підхід «Builder Pattern» полягає у створенні двох Docker-файлів і sh-скрипта:
- Dockerfile.build — збирає додаток (витягає залежності, компілює і т. д.).
- Dockerfile — запускає додаток.
- build.sh — копіює артифакт, отриманий з Dockerfile.build, в контейнер, що збирається з Dockerfile.
Приклад «Builder Pattern». Вихідний код прикладу можна отримати на GitHub .
Dockerfile.build
FROM golang:1.12.4-stretch # Change worck directory WORKDIR /go/src/github.com/zhooravell/docker-multi-stage-builds/builder-pattern # Copy go code & dep files to worck directory COPY main.go Gopkg.toml Gopkg.toml ./ # Install dep, packages and build application RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh \ && dep version \ && dep ensure \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
Dockerfile
FROM alpine:latest # Add ssl support RUN апк --no-cache add ca-certificates WORKDIR /root/ COPY app . CMD ["./app"]
#!/usr/bin/env bash echo Building docker-multi-stage-builds/builder-pattern:build # Билдим образ додаток (залежно, компіляція) docker build -t docker-multi-stage-builds/builder-pattern:build . -f Dockerfile.build # Створюємо контейнер з коротким ім'ям extract docker container create --name extract docker-multi-stage-builds/builder-pattern:build # Копіюємо артефакт з контейнера на хост-машину docker container cp extract:/go/src/github.com/zhooravell/docker-multi-stage-builds/builder-pattern/app ./app # Видаляємо контейнер docker container rm -f extract echo Building docker-multi-stage-builds/builder-pattern:latest # Збираємо образ з додатком скомпільованим docker build --no-cache -t docker-multi-stage-builds/builder-pattern:latest . # Видаляємо артефакт rm ./app
Запустимо контейнер і переконаємося, що все працює, як очікувалося:
$ docker run -p 8080:8080 docker-multi-stage-builds/builder-pattern
В результаті виходить дуже маленький образ, з мінімальним набором пакетів/залежностей — тільки те, що потрібно для запуску програми. Production-образ не містить інструментів складання, компіляції, систем керування версіями.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker-multi-stage-builds/builder-pattern latest 4be00adf69b0 16 seconds ago 13.8 MB docker-multi-stage-builds/builder-pattern build 3f0177d07175 20 seconds ago 819MB
Що ж тоді multi-stage build? І навіщо він потрібен?
Багатоступінчастий білд дозволяє досягти того ж результату, але без bash-скриптів, без кількох Docker-файлів. Це досягається за рахунок використання декількох інструкцій FROM. В результаті попередній приклад буде виглядати так:
FROM golang:1.12.4-stretch as builder # Change worck directory WORKDIR /go/src/github.com/zhooravell/docker-multi-stage-builds/go-multi-stage-build # Copy go code & dep files to worck directory COPY main.go Gopkg.toml Gopkg.toml ./ # Install dep, packages and build application RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh \ && dep version \ && dep ensure \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest # Add ssl support RUN апк --no-cache add ca-certificates WORKDIR /root/ # Copy just the built artifact from the previous stage into this new stage # The Go SDK and any intermediate artifacts are left behind, and not saved in the final image. COPY --from=builder /go/src/github.com/zhooravell/docker-multi-stage-builds/go-multi-stage-build/app ./ EXPOSE 8080 CMD ["./app"]
Вся «хитрість» полягає в конструкції COPY —from=builder. Вона копіює артефакт з кроку з аліасом builder (FROM golang:1.12.4-stretch as builder). Зберемо наш контейнер:
$ docker build --no-cache -t docker-multi-stage-builds/go:latest .
Давайте розглянемо ще приклад використання multi-stage builds.
Angular і Docker multi-stage builds
На основі docker multi-stage build можна реалізувати повний життєвий цикл angular-додатки:
- Розробка (npm start).
- Збірка (ng build —prod).
- Деплой (nginx).
Вихідний код прикладу можна отримати на GitHub . Docker-файл буде містити 3 кроки (FROM) складання і виглядатиме так:
### STAGE 1: Develop ### FROM node:11.14.0-alpine as develop USER node RUN mkdir /home/node/.npm-global && mkdir /home/node/logs ENV PATH=/home/node/.npm-global/bin:$PATH ENV NPM_CONFIG_PREFIX=/home/node/.npm-global ENV HOME=/home/node WORKDIR $HOME/app RUN npm i -g npm RUN npm install -g @angular/cli && npm cache clean --force EXPOSE 4200 CMD [ "node" ] ### STAGE 2: Build ### FROM develop as builder USER root COPY app . RUN npm install && ng build --prod --output-path=dist ### STAGE 3: Setup ### FROM nginx:1.15.12-alpine # Remove default nginx website RUN rm -rf /usr/share/nginx/html/* # From 'builder' stage copy over the artifacts in dist folder to default nginx public folder COPY --from=builder /home/node/app/dist /usr/share/nginx/html
Перший крок (develop) містить у собі установку пакета Angular CLI і буде використовуватися для розробки. Другий крок (builder) призначений для складання додатка: RUN npm install && ng build —prod —output-path=dist . Третій крок призначений для копіювання артефакту (сбилдженого додатки) в контейнер з HTTP-сервер.
Для етапу розробки буде використовуватися docker-compose. Починаючи з версії 3.4, docker-compose підтримує build.target , що дозволяє зупинити збірку контейнера на конкретному кроці (в нашому випадку цей крок — develop ).
version: "3.4" services: angular: build: context: . target: develop # use stage develop ports: - 4200:4200 volumes: - ./app:/home/node/app:rw command: - /bin/sh - -c - | cd /home/node/app && npm install && start npm
Виконавши команду docker-compose up , ми отримаємо повноцінно працює оточення для розробки Angular-додатки (компіляція TypeScript, релоад браузера і т. д.).
Щоб отримати складання програми, готову до деплою, потрібно виконати команду:
$ docker build --no-cache -t docker-multi-stage-builds/go:latest .
Запуск контейнера з HTTP-сервером і Angular-додатком виконується так:
$ docker run -p 8080:80 docker-multi-stage-builds/angular:latest
Висновки
Docker multi-stage build дозволяє оптимізувати складання образів. Зробити контейнери більш «легкими», а також уніфікувати процес розробки, складання та деплоя.
Сподіваюся, ця інформація була вам корисна.
Опубліковано: 26/04/19 @ 10:00
Розділ Різне
Рекомендуємо:
Програміст Антон Максимчук – про роботу в IBM, труднощі легалізації в Польщі й повернення до України
DOU Ревізор в Innovecs: цілодобовий R&D-центр на п'ять поверхів
Еволюція зарплат: як Junior Java Developer за 11 років став PM c $8000
Подорожі, розвиток та рівні права усім: web-аналітик Галина Харківська про роботу в Booking та життя в Амстердамі
Увагу Google Recaptcha v3 + Contact Form 7