* Yasen (Yet Another Search Engine) – первоначальная архитектура поискового движка.
* Немного о старой схеме деплоя и её боли – buildbot, chef, git, monit, haproxy.
* Docker – простота и мощь в одной команде.
* Настраиваем запуск демона – что нужно знать.
* Dockerfile – проблемы и решения.
* Swarm, Kubernetes, Rancher – обзор вариантов оркестрации.
* Простой путь – docker-compose, и как его готовить.
* Разбираемся с сетью – bridge, host, overlay, macvlan, none.
* Root или не root в контейнере? Выбираем подходящее решение.
* Shared volumes и проблема права доступа к файлам.
* User namespaces – как и зачем?
* Docker и linux capabilities – добавляем безопасности.
* Нюансы ограничения ресурсов контейнеру: memory, cpu, swap.
* Stateful & Stateless в docker
* Автоматизация деплоя через docker-compose.
* Итоговая архитектура и процесс выкатки в production.
5. ++ 1 500 000 поисков в день
++ Поиск – опрос 200 партнеров в realtime
++ 1 000 поисков в минуту в пики
aviasales.ru
6. ++ 1 500 000 поисков в день
++ 15 000 предложений в одном ответе
++ Поиск – опрос 200 партнеров в realtime
++ 1 000 поисков в минуту в пики
aviasales.ru
7. ++ 1 500 000 поисков в день
++ 15 000 предложений в одном ответе
++ Поиск – опрос 200 партнеров в realtime
++ 1 минута на отдачу билетов
++ 1 000 поисков в минуту в пики
aviasales.ru
33. Муравей (ant)
++ Приоритеты: low, normal, high
++ Шлёт информацию о найденных билетах в Redis
++ Сохраняет статистику в разные базы данных
34. Муравей (ant)
++ Приоритеты: low, normal, high
++ Шлёт информацию о найденных билетах в Redis
++ Сохраняет статистику в разные базы данных
++ Stateless
38. Очередь (burlesque)
++ 1 процесс на одну ноду
++ Go + leveldb
++ Умеет 3000+ rps concurrent read/write
39. Очередь (burlesque)
++ 1 процесс на одну ноду
++ Go + leveldb
++ Умеет 3000+ rps concurrent read/write
++ Простой HTTP-интерфейс для работы
40. Очередь (burlesque)
++ 1 процесс на одну ноду
++ Go + leveldb
++ Умеет 3000+ rps concurrent read/write
++ Простой HTTP-интерфейс для работы
++ Opensource: https://github.com/KosyanMedia/burlesque
42. Что же не так?
++ Время на подъем сервиса для разработки
43. Что же не так?
++ 2 часа на деплой всей системы
++ Время на подъем сервиса для разработки
44. Что же не так?
++ 2 часа на деплой всей системы
++ Monit – тупит на большом количестве процессов
++ Время на подъем сервиса для разработки
45. Что же не так?
++ 2 часа на деплой всей системы
++ Chef – настройка серверов
++ Monit – тупит на большом количестве процессов
++ Время на подъем сервиса для разработки
51. Зачем?
++ Единое окружение везде
++ Ориентирован на DevOps
++ Никаких правок на горячую в коде production
++ Сборка образа где угодно
52. Зачем?
++ Единое окружение везде
++ Ориентирован на DevOps
++ Никаких правок на горячую в коде production
++ Простота отката
++ Сборка образа где угодно
71. В поисках серебряной пули
++ Хочется прозрачности
++ Простые вещи дешевле поддерживать
72. В поисках серебряной пули
++ Хочется прозрачности
++ Простые вещи дешевле поддерживать
++ Ещё одна технологическая прослойка
73. В поисках серебряной пули
++ Хочется прозрачности
++ Простые вещи дешевле поддерживать
++ Ещё одна технологическая прослойка
++ Вероятность вернуться к прошлой инфраструктуре
74. В поисках серебряной пули
++ Хочется прозрачности
++ Простые вещи дешевле поддерживать
++ Ещё одна технологическая прослойка
++ Вероятность вернуться к прошлой инфраструктуре
++ Время, время, время…
89. Проблемы? Конечно!
++ Root по умолчанию
++ Наследуется от одного образа
++ Слишком толсто – если плодить слои
90. Проблемы? Конечно!
++ Root по умолчанию
++ Наследуется от одного образа
++ Слишком толсто – если плодить слои
++ COPY всегда root
91. Проблемы? Конечно!
++ Root по умолчанию
++ Наследуется от одного образа
++ Слишком толсто – если плодить слои
++ COPY всегда root
++ COPY в конце или “прощай, кэш”
94. ++ Создаваемые файлы тоже root
Контейнерный root
++ Root в контейнере = root на host-машине
95. ++ Создаваемые файлы тоже root
Контейнерный root
++ Root в контейнере = root на host-машине
++ Процесс может не встать из-под root
96. ++ Создаваемые файлы тоже root
Контейнерный root
++ Root в контейнере = root на host-машине
++ Процесс может не встать из-под root
++ Non-root – наш выбор
104. А как же stateful?
++ Проблем нет только у stateless
105. А как же stateful?
++ Проблем нет только у stateless
++ Простой путь – общие папки
106. А как же stateful?
++ Проблем нет только у stateless
++ Простой путь – общие папки
++ Более сложный – etcd, consul, redis
107. А как же stateful?
++ Проблем нет только у stateless
++ Простой путь – общие папки
++ Более сложный – etcd, consul, redis
++ Комбо – забираем состояние с мастер-ноды
118. User namespaces
++ Появились с версией 1.10
++ Root контейнера = non uid-0 на host-машине
++ По умолчанию отключено
119. User namespaces
++ Появились с версией 1.10
++ Root контейнера = non uid-0 на host-машине
++ По умолчанию отключено
++ --userns-remap в опциях запуска демона
129. Network mode: bridge
++ На самом деле NAT
++ Отдельный локальный IP для контейнера
++ Изоляция порта внутри контейнера
130. Network mode: bridge
++ На самом деле NAT
++ Отдельный локальный IP для контейнера
++ Изоляция порта внутри контейнера
++ Суёт свой хвост в iptables – админы недовольны
133. Network mode: host
++ Сеть хост-машины как есть в контейнере
++ Host port = container port
134. Network mode: host
++ Сеть хост-машины как есть в контейнере
++ Host port = container port
++ Свобода iptables от вмешательств Docker
135. Network mode: host
++ Сеть хост-машины как есть в контейнере
++ Host port = container port
++ Свобода iptables от вмешательств Docker
++ Наш выбор!
142. Network mode: macvlan
++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+
++ Только одна сеть на сетевой интерфейс
143. Network mode: macvlan
++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+
++ Только одна сеть на сетевой интерфейс
++ Каждому контейнеру уникальный MAC
144. Network mode: macvlan
++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+
++ Только одна сеть на сетевой интерфейс
++ Каждому контейнеру уникальный MAC
++ Прямой доступ к другим контейнерам, минуя gateway
145. Network mode: macvlan
++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+
++ Только одна сеть на сетевой интерфейс
++ Нет доступа из контейнера к хост-машине по IP
++ Каждому контейнеру уникальный MAC
++ Прямой доступ к другим контейнерам, минуя gateway
154. Limit everything
++ CPU: --cpu-shares, --cpuset-cpus
++ Memory: --memory, --memory-reservation
++ Swap: --memory-swap, --memory-swappiness
++ Storage: --device-read-bps, --device-write-bps
++ И это далеко не всё
157. Собираем всё вместе
++ Динамический docker-compose.yml
++ Одна сущность контейнера – один YAML template
158. Собираем всё вместе
++ Динамический docker-compose.yml
++ Одна сущность контейнера – один YAML template
++ Множим контейнеры через генератор конфига
159. Собираем всё вместе
++ Динамический docker-compose.yml
++ Одна сущность контейнера – один YAML template
++ Множим контейнеры через генератор конфига
++ scale bee=10 ant=1 goqueue=1
165. Шаблонизируем
++ Секция docker-compose как шаблон
++ Есть %ЗАМЕНЯЕМЫЕ% значения
++ А ещё переменные окружения
++ Все константы и настройки – env.sh
++ Сборка всех шаблонов в один на чистом BASH
172. Деплой на сервер
++ Забираем свежий код из git
++ Генерируем docker-compose.yml по окружению
173. Деплой на сервер
++ Забираем свежий код из git
++ Генерируем docker-compose.yml по окружению
++ Собираем все образы
174. Деплой на сервер
++ Забираем свежий код из git
++ Генерируем docker-compose.yml по окружению
++ Собираем все образы
++ Запускаем контейнеры – docker-compose --no-build up
180. Выкатка на ферму
++ grep production cluster.yml | cut -d: -f1
++ Запуск deploy-скрипта на всех выбранных нодах
181. Выкатка на ферму
++ grep production cluster.yml | cut -d: -f1
++ Запуск deploy-скрипта на всех выбранных нодах
++ И всё это одновременно на всех нодах
182. Выкатка на ферму
++ grep production cluster.yml | cut -d: -f1
++ Запуск deploy-скрипта на всех выбранных нодах
++ И всё это одновременно на всех нодах
++ Снова BASH: background processes & wait
183. Выкатка на ферму
++ grep production cluster.yml | cut -d: -f1
++ Запуск deploy-скрипта на всех выбранных нодах
++ И всё это одновременно на всех нодах
++ Снова BASH: background processes & wait
++ Success or fail? Шлем в slack
184. Выкатка на ферму
++ grep production cluster.yml | cut -d: -f1
++ Запуск deploy-скрипта на всех выбранных нодах
++ И всё это одновременно на всех нодах
++ Снова BASH: background processes & wait
++ Success or fail? Шлем в slack
187. В сухом остатке
++ Полная миграция за 150 человеко-часов
++ 50 человеко-часов на написание системы
188. В сухом остатке
++ Полная миграция за 150 человеко-часов
++ 500 строк BASH'а в 5-ти файлах на управление
++ 50 человеко-часов на написание системы
189. В сухом остатке
++ Полная миграция за 150 человеко-часов
++ 500 строк BASH'а в 5-ти файлах на управление
++ Масштабирование в одном месте
++ 50 человеко-часов на написание системы
190. В сухом остатке
++ Полная миграция за 150 человеко-часов
++ 500 строк BASH'а в 5-ти файлах на управление
++ Масштабирование в одном месте
++ Автоматизация настройки dev-окружения
++ 50 человеко-часов на написание системы