Сборка сервисов в Docker
через Docker-в-Docker
Шамбир Сергей
Ведущий инженер iSpring
Slide 2
Slide 2 text
Продукт X: переход к микросервисам
Величайший враг прячется там, где вы будете меньше
всего его искать.
Гай Юлий Цезарь
Slide 3
Slide 3 text
REST
REST
REST
сокеты
Структура продукта X (до перехода на Docker)
Монолит
на PHP
Монолит
на PHP
Frontend
Микросервис
на Go
Микросервис
на Node.js
SPA
iframe
Slide 4
Slide 4 text
REST
REST
REST
сокеты
Структура продукта X (в скором будущем)
Монолит
на PHP
Монолит
на PHP
Frontend
Микросервис
на Go
Микросервис
на Node.js
SPA
SPA
Микросервис
на Go
Микросервис
на Go
Микросервис
на Go
Микросервис
на Go
Микросервис
на Node.js
iframe
iframe
SPA
Микросервис
на Go
Slide 5
Slide 5 text
Deploy X
kustomize
Реестр dev
Реестр prod
Slide 6
Slide 6 text
Build X
Service X
Frontend X
Service Y
Frontend Y
Service Z
Container
x:v1.2.3
Container
y:???
Container
z:???
Slide 7
Slide 7 text
Резюмируя
Не надо ограничиваться унификацией развёртывания
образов
Подумайте об унификации сборки контейнеров из git
Используйте docker, чтобы упростить разработку
Slide 8
Slide 8 text
Сборка отдельно, деплой совместно
Разделяй и властвуй.
Гай Юлий Цезарь
Slide 9
Slide 9 text
Сборка: make + docker build
docker build -t
{branch.buildNo} .
docker push
{branch.buildNo}
Makefile
build:
dep ensure
go build
-o ... ...
Dockerfile
FROM debian
ADD ... /go/bin/outyet
ENTRYPOINT
/go/bin/outyet
EXPOSE 8080
make build
Сервис
на Go
Slide 10
Slide 10 text
Сборка: только docker build
https://blog.golang.org/docker
docker build -t
{branch.buildNo} .
docker push
{branch.buildNo}
Dockerfile
FROM golang
ADD .
/go/src/.../outyet
RUN go install
.../outyet
ENTRYPOINT
/go/bin/outyet
EXPOSE 8080
Сервис
на Go
Slide 11
Slide 11 text
Сборка: multi-stage docker build
https://
blog.codeship.com/building-minimal-docker-c
ontainers-for-go-applications/
docker build -t
{branch.buildNo} .
docker push
{branch.buildNo}
Dockerfile
FROM golang:alpine as builder
COPY . $GOPATH/src/outyet
WORKDIR $GOPATH/src/outyet
RUN go build -o /go/bin/outyet
FROM scratch
COPY --from=builder
/go/bin/outyet /go/bin/outyet
ENTRYPOINT ["/go/bin/outyet"]
Сервис
на Go
Slide 12
Slide 12 text
Нюансы сборки из scratch
Проблемы:
У вас нет пакетного менеджера и командной оболочки
У вас нет SSL сертификатов (нельзя выполнять https
запросы)
У вас нет данных о часовых поясах (tzdata)
Решения:
1. github.com/jeremyhuiskamp/golang-docker-scratch
2. использовать alpine
Slide 13
Slide 13 text
Добавим трудностей
Пусть фронтенд будет сложным SPA
Установка зависимостей через npm install
Сборка через npm run dist
Запуск модульных тестов и linter через npm run test
Slide 14
Slide 14 text
Сборка: добавляем frontend
docker build -t
{branch.buildNo} .
docker push
{branch.buildNo}
Dockerfile
FROM node:11-alpine as frontend
COPY ./www /usr/src/www
RUN npm install && npm run dist
FROM golang:alpine as builder
COPY . $GOPATH/src/outyet
WORKDIR $GOPATH/src/outyet
RUN go build -o /go/bin/outyet
FROM scratch
COPY --from=builder /go/bin/outyet /go/bin/outyet
COPY –from=frontend /usr/src/www/dist/ /go/bin/outyet/www
ENTRYPOINT ["/go/bin/outyet"]
Сервис
на Go
Slide 15
Slide 15 text
Добавим трудностей
Пусть фронтенд будет сложным SPA
Установка зависимостей через npm install
Сборка через npm run dist
Запуск модульных тестов и linter через npm run test
Пусть фронтенд лежит в отдельном репозитории
А в чём проблема?
git submodule add git@git.x.com/frontend
Slide 16
Slide 16 text
Немного о сабмодулях
Измени подмодуль в
ветке A
Как возненавидеть свою работу
Измени подмодуль в
ветке B
Сделай merge
Ты ещё
считаешь, что
git submodule –
это круто?
Да!
Нет
Slide 17
Slide 17 text
Сборка: добавление frontend через скрипт
docker build -t
{branch.buildNo} .
docker push
{branch.buildNo}
Dockerfile
FROM node:11-alpine as frontend
COPY ./www /usr/src/www
RUN npm install && npm run dist
if ! [ -d ${DIR} ]; then
git clone ${REPO} ${DIR}
fi
cd ${DIR}
git reset --hard
git clean -fdx
git fetch origin
git checkout origin/${BRANCH}
Скрипт обновления
frontend
Сервис
на Go
Slide 18
Slide 18 text
Сборка: docker-контейнер с frontend
docker build -t {branch.buildNo} . --build-
arg
"FRONT=harbour.x.com/frontend:$
{BRANCH.BUILD_NO}"
docker push
{branch.buildNo}
Dockerfile
ARG FRONT=nil
FROM ${FRONT} as frontend
FROM golang:alpine as builder
COPY . $GOPATH/src/outyet
WORKDIR $GOPATH/src/outyet
RUN go build -o /go/bin/outyet
FROM scratch
Сервис
на Go
Фронтенд
docker build -t
{branch.buildNo} .
docker push {branch.buildNo}
Slide 19
Slide 19 text
Резюмируя
Для каждого микросервиса:
1. Использовать multi-stage docker builds + build args
2. Конфигурировать сервис CI для сбороки frontend, сборки
сервиса и развёртывания продукта по цепочке
Slide 20
Slide 20 text
Согласованный deploy
kustomize
Container
x:v1.2.3
Container
x:TASK-981
Container
x:master
Container
x:v1.2.4
Кто выбирает версии
контейнеров?
Где хранятся конфиги
kustomize и k8s?
Slide 21
Slide 21 text
Согласование версий: подход от 2GIS
Service X
Frontend X
Service Y
Frontend Y
Service Z
Монорепозиторий:
Service X
Frontend X
Service Y
Fronten Y
Service Z
https://youtu.be/RSTHex_rKBU
Подход к Continuous Deployment в
микросервисной архитектуре
/ Алексей Баитов (2ГИС)
Container
x:v1.2.3
Container
y:v2.0.19
Container
z:master
Сервис деплоя на
Python
С конфигами на Python
Slide 22
Slide 22 text
Резюмируя
Собирайте проекты в Docker-контейнере
Подумайте, как автоматизировать согласование версий
микросервисов
Slide 23
Slide 23 text
Наше решение: X Platform
Великие дела надо совершать, а не обдумывать их
бесконечно.
Гай Юлий Цезарь
Slide 24
Slide 24 text
Схема сборки
Скрипт на Bash
Запускает в Docker контейнере скрипт на Python3
X Platform
bin
x-platform
src
сервис
сервис
k8s
…
x-platform.yml
x-platform.py
Скрипт на Python3
~600 строк
Читает x-platform.yml
Выполняет сборку и деплой
Slide 25
Slide 25 text
Схема сборки
…
services:
zbackend:
dir: src/zbackend
git:
remote: git@git.x.com/zbackend
reference: origin/master
dockerBuilder:
image: builders/zbackend:newest
workdir: /go/src/x/zbackend
docker:
image: zbackend
scripts:
build:
- make build
test:
- make test
X Platform
bin
x-platform
src
сервис
сервис
k8s
…
x-platform.yml
x-platform.py
Контейнеры для сборки контейнеров
Каталог с контейнерами
для сборки контейнеров
X Platform
bin
x-update-builder
builders
zbackend
zfrontend
k8s
x-platform.yml
x-platform.py
Dockerfile
Файл описания контейнера-сборщика
Исходников нет
Только база + apt-get
Скрипт для сборки контейнеров,
собирающего контейнеры
x-update-builder zbackend
Slide 28
Slide 28 text
Тег образа –
это sha-1
последнего
коммита
Схема сборки
x-platform build --services zbackend
Обновление репозитория
Сборка
Unit тесты
docker build
docker push
docker push
В реестре или
локально есть
образ с таким
sha-1?
docker pull
Нет Да
Slide 29
Slide 29 text
Плюсы X Platform как системы сборки контейнеров
Не требует монорепозитория
Тегирует образ по sha-1 коммита
Быстрая локальная сборка
Быстрая сборка на сервере
Относительно прост в реализации: 600 строк на Python, 2-3
недели разработки
Slide 30
Slide 30 text
Резюмируя
Свой велосипед – это хорошо, если его код
минималистичен, а выгоды от автоматизации много
Положите свой велосипед в Docker
Slide 31
Slide 31 text
Альтернатива: flant/dapp
Не господство устранено, а переменили господина.
Марк Юний Брут
Slide 32
Slide 32 text
Что такое Dapp
https://flant.github.io/dapp/
Открытый проект компании Flant
Написан на Go
Выполняет сборку образов и согласованный deploy
Умеет работать с моно- и мультирепозиториями
Умеет кешировать все шаги сборки всех контейнеров
Умеет тегировать контейнеры по sha-1 коммита, по ветке,
по номеру билда
Slide 33
Slide 33 text
Сомнительные особенности Dapp
Заменяет Dockerfile
Поддерживает Ansible
Deploy только через Helm + Kubernetes
Slide 34
Slide 34 text
Резюмируя
Используйте dapp как выбор по умолчанию для
автоматизации CI
Пишите свой скрипт, если dapp не подходит
Не полагайтесь на TeamCity, Gitlab CI, Buildbot – они by
design не рассчитаны на микросервисы и Docker