Legacy в коробочке
Dev-среда на базе Kubernetes
Илья Сауленко
Avito
Как выглядит микросервисная
архитектура?
Суровая реальность
Монолит надо разрабатывать:
● Поддерживать старый код
● Разрабатывать новые фичи
Монолит надо тестировать:
● Тестировать новые фичи
● Интегрировать с микросервисами
Среды в Avito: раньше
LXC
dev:
test:
Нужны новые среды!
Что не нравится?
Vagrant-окружения слишком хрупкие
Vagrant/Chef-конфигурации сильно отличаются от продакшена
Разные решения для dev- и test-сред
Тесты используют общие хранилища данных
Общие базы/сфинксы etc
Микросервисы в Avito
Среды в Avito: сейчас
Kubernetes — это сложно!
Настраивать сеть
Ставить etcd
Готовить сертификаты
Kubernetes — это сложно!
Minikube
Kubernetes — это сложно!
Minikube
...или kubeadm
Kubernetes — это перебор!
У нас же всего одно приложение на одном локальном сервере!
Зачем оркестрация? Мы просто хотим писать код!
Kubernetes — это перебор!
Раздаёт IP-адреса контейнерам автоматически
kube-dns для service discovery
Ingress controller для HTTP-роутинга
Readiness probe
Heapster для мониторинга отдельных компонентов
Микросервис vs монолит:
найдите 10 отличий
Среднестатистический микросервис
Приложение
Хранилища данных
Зависимости от других сервисов
Описание сборки (Dockerfile)
Описание деплоя (Chart.yaml)
Приложение
Dockerfile Chart.yaml
Данные
Сторонний сервис
Монолит
Приложение
Puppet + python
+ bash
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Приложение
Puppet + python
+ bash
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Базы в Docker-контейнерах
Базы в Docker-контейнерах
Immutable
Базы в Docker-контейнерах
Immutable
Ограничены по размеру
Как быть с большими базами?
Как быть с большими базами?
1. Никак — ходить в продакшен
Как быть с большими базами?
1. Никак — ходить в продакшен
2. Никак — поднимать пустой сервер без данных
Как быть с большими базами?
1. Никак — ходить в продакшен
2. Никак — поднимать пустой сервер без данных
3. Поднимать сервер без данных и накатывать тестовые данные
Как быть с большими базами?
1. Никак — ходить в продакшен
2. Никак — поднимать пустой сервер без данных
3. Поднимать сервер без данных и накатывать тестовые данные
4. Семплировать часть боевых данных
Как быть с большими базами?
1. Никак — ходить в продакшен
2. Никак — поднимать пустой сервер без данных
3. Поднимать сервер без данных и накатывать тестовые данные
4. Семплировать часть боевых данных
5. Сделать пул серверов на снапшотах файловых систем (ZFS, etc)
Docker commit
Не всегда образ можно собрать с помощью docker build
Например, если нужно сделать образ SphinxSearch из базы данных,
запущенной в соседнем контейнере
Docker commit
$ docker run -d --name db-container db-image
$ docker run -d --name sphinx-container --link db-container
sphinxsearch
$ docker exec sphinx-container indexer -c sphinx.conf --all
$ docker stop sphinx-container
$ docker commit -m “sphinx indexes” sphinx-container
sphinx-image
Docker commit: альтернативы
Ansible Container
Packer
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Puppet + python
+ bash
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Puppet + python
+ bash
Сборка кода: версии софта
Сборка кода: версии софта
В Vagrant одна версия node.js, на тестовых серверах — другая
Сборка кода: версии софта
В Vagrant одна версия node.js, на тестовых серверах — другая
docker build обычно решает большую часть проблем
Сборка кода: когда docker build не хватает
Сборка кода: когда docker build не хватает
Для сборки и запуска приложений — разный набор софта
Сборка кода: когда docker build не хватает
Для сборки и запуска приложений — разный набор софта
Внешние зависимости (например, собрать словарь из базы данных)
Build container
base OS
build dependencies
build image:
Build container
base OS
build dependencies
sources
build image:
+
Build container
base OS
build dependencies
sources
build image:
app
+
=
Build container
app
Build container
base OS
runtime dependencies
app image:
app
Build container
base OS
runtime dependencies
app
app image:
app
Build container
base OS
build dependencies
base OS
runtime dependencies
sources
app
build image: app image:
app
+
=
Build container
Dockerfile.build:
FROM debian
RUN apt-get install php composer
nodejs npm
ENTRYPOINT [“make”, “build”]
…
$ docker build -f Dockerfile.build
-t build-image .
$ docker run -v $PWD:/app/
build-image
Dockerfile:
FROM debian
RUN apt-get install php
COPY ./build/ /app/
…
$ docker build -t run-image .
Build container: альтернативы
IMPORT/EXPORT в Rocker
mount в dapp
Multi-stage builds в Docker 17.05
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Dockerfile
Puppet + python
+ bash
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Dockerfile
Puppet + python
+ bash
Helm для деплоя
Почему Helm?
Менеджер релизов: приложение + конфигурация
Шаблонизация Kubernetes-ресурсов
Использует существующие Kubernetes-примитивы
Helm: альтернативы
AppController
Flux
Spinnaker
Helm Chart
Chart.yaml
templates/ charts/метаданные
k8s-ресурсы
рекурсия
values.yaml
значения по умолчанию,
публичный интерфейс чарта
deployment.yaml
configmap.yaml
ingress.yaml
service.yaml
$ helm upgrade --install --wait release-name ./
Helm Kubernetes
Pod
Container
Container
Container
...
Pod Container
Декларативный деплой
Chart
Readiness probe
Readiness probe
> GET /healthz
< 200 OK
Readiness probe
> GET /healthz
< 200 OK
> GET /healthz
< 500 Internal Server Error
$ helm upgrade --install --wait release-name ./
$ echo $?
1
Readiness probe = Smoke test
Helm Kubernetes
Pod
Container
Container
Container
...
Pod Container
Helm: проблемы
Молодой, быстро развивающийся
Нет фидбэка в процессе установки*
go/template внутри yaml**
* https://github.com/kubernetes/helm/pull/2386
** https://github.com/ksonnet/ksonnet-lib
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Dockerfile Chart.yaml
Приложение
Данные
Сторонний сервис
Сторонний сервис
Сторонний сервис
Данные
Данные
Данные
Dockerfile Chart.yaml
Условные зависимости
“Хочу тестовую среду, у которой будет своя база, локально поднятые
сервисы A и B, а за сервисом C пусть ходит в staging”
Условные зависимости
“Хочу тестовую среду, у которой будет своя база, локально поднятые
сервисы A и B, а за сервисом C пусть ходит в staging”
“Мне нужно разрабатывать новый сервис D локально и интегрировать его с
монолитом. Остальные зависимости можно вообще не поднимать”
Условные зависимости
values.yaml, values.dev.yaml, values.test.yaml
Условные зависимости
values.yaml, values.dev.yaml, values.test.yaml
serviceA.location: ‘on-cluster’
Условные зависимости
values.yaml, values.dev.yaml, values.test.yaml
serviceA.location: ‘on-cluster’
{{- if eq .Values.location “on-cluster” -}}
…
{{- end -}}
Условные зависимости
values.yaml, values.dev.yaml, values.test.yaml
requirements.yaml
Условные зависимости
Приложение
Сторонний сервис
Данные
Dockerfile Chart.yaml
Developer Experience
vboxfs:
● Медленное чтение
● Нет поддержки смены прав внутри дерева
● inotify не работает
kubectl:
● Слишком fine-grained
● “kubectl exec” — это вам не терминал
Developer Experience: проблемы
Скрипт для автоматизации рутины: логи, ssh, etc
CLI-дашборд, показывающий самое важное
lsyncd вместо vboxfs
Облако вместо VirtualBox
Draft?
Developer Experience: решение
Что получилось?
Что получилось?
Docker + Kubernetes + Helm (+ VirtualBox + Minikube)
Переиспользование образов при разработке и тестировании
“Legacy в коробочке”, поднимаемое одной командой локально или в кластере
Спасибо!
Вопросы?
Илья Сауленко, Avito
@mynameiswhm

Legacy в коробочке. Dev-среда на базе Kubernetes / Илья Сауленко (Avito)