Aviasales: миграция поискового движка в docker / Дмитрий...

Post on 16-Apr-2017

452 views 7 download

Transcript of Aviasales: миграция поискового движка в docker / Дмитрий...

Миграция поискового движка в Docker

Дмитрий Кузьменковwww.aviasales.ru

aviasales.ru

++ 1 500 000 поисков в день

aviasales.ru

++ 1 500 000 поисков в день

++ 1 000 поисков в минуту в пики

aviasales.ru

++ 1 500 000 поисков в день

++ Поиск – опрос 200 партнеров в realtime

++ 1 000 поисков в минуту в пики

aviasales.ru

++ 1 500 000 поисков в день

++ 15 000 предложений в одном ответе

++ Поиск – опрос 200 партнеров в realtime

++ 1 000 поисков в минуту в пики

aviasales.ru

++ 1 500 000 поисков в день

++ 15 000 предложений в одном ответе

++ Поиск – опрос 200 партнеров в realtime

++ 1 минута на отдачу билетов

++ 1 000 поисков в минуту в пики

aviasales.ru

Yasen – что за зверь?

Yasen – что за зверь?++ Yet Another Search ENgine

Yasen – что за зверь?++ Yet Another Search ENgine

++ Python 3.4 & Tornado 4.2

Yasen – что за зверь?++ Yet Another Search ENgine

++ 8 серверов

++ Python 3.4 & Tornado 4.2

Yasen – что за зверь?++ Yet Another Search ENgine

++ 8 серверов

++ Python 3.4 & Tornado 4.2

++ Первый ответ за 200 ms

Как оно работает

Как оно работает

HAProxy

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

queue

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

ant.0

ant.1queue

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

ant.0

ant.1

Redis

queue

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

MySQLPostgres

RedisRabbitMQ

ant.0

ant.1

Redis

queue

Как оно работает

HAProxy

bee.0

bee.1

bee.2

bee.3

MySQLPostgres

RedisRabbitMQ

ant.0

ant.1

Redis

watcher configs

queue

Пчела (bee)

Пчела (bee)++ Обслуживает HTTP-запросы на поиск

Пчела (bee)++ Обслуживает HTTP-запросы на поиск

++ Асинхронная на Tornado

Пчела (bee)++ Обслуживает HTTP-запросы на поиск

++ Асинхронная на Tornado

++ Цикл жизни 30 минут

Пчела (bee)++ Обслуживает HTTP-запросы на поиск

++ Асинхронная на Tornado

++ Цикл жизни 30 минут

++ 16 пчел на одной ноде

Наблюдатель (watcher)

Наблюдатель (watcher)++ 1 процесс на одну ноду

Наблюдатель (watcher)++ 1 процесс на одну ноду

++ Следит за изменениями файлов настроек

Наблюдатель (watcher)++ 1 процесс на одну ноду

++ Следит за изменениями файлов настроек

++ Обновляет настройки пчел в runtime

Муравей (ant)

Муравей (ant)++ Приоритеты: low, normal, high

Муравей (ant)++ Приоритеты: low, normal, high

++ Шлёт информацию о найденных билетах в Redis

Муравей (ant)++ Приоритеты: low, normal, high

++ Шлёт информацию о найденных билетах в Redis

++ Сохраняет статистику в разные базы данных

Муравей (ant)++ Приоритеты: low, normal, high

++ Шлёт информацию о найденных билетах в Redis

++ Сохраняет статистику в разные базы данных

++ Stateless

Очередь (burlesque)

Очередь (burlesque)++ 1 процесс на одну ноду

Очередь (burlesque)++ 1 процесс на одну ноду

++ Go + leveldb

Очередь (burlesque)++ 1 процесс на одну ноду

++ Go + leveldb

++ Умеет 3000+ rps concurrent read/write

Очередь (burlesque)++ 1 процесс на одну ноду

++ Go + leveldb

++ Умеет 3000+ rps concurrent read/write

++ Простой HTTP-интерфейс для работы

Очередь (burlesque)++ 1 процесс на одну ноду

++ Go + leveldb

++ Умеет 3000+ rps concurrent read/write

++ Простой HTTP-интерфейс для работы

++ Opensource: https://github.com/KosyanMedia/burlesque

Что же не так?

Что же не так?++ Время на подъем сервиса для разработки

Что же не так?

++ 2 часа на деплой всей системы

++ Время на подъем сервиса для разработки

Что же не так?

++ 2 часа на деплой всей системы

++ Monit – тупит на большом количестве процессов

++ Время на подъем сервиса для разработки

Что же не так?

++ 2 часа на деплой всей системы

++ Chef – настройка серверов

++ Monit – тупит на большом количестве процессов

++ Время на подъем сервиса для разработки

Контейнеризация?

Зачем?

Зачем?++ Единое окружение везде

Зачем?++ Единое окружение везде

++ Сборка образа где угодно

Зачем?++ Единое окружение везде

++ Ориентирован на DevOps

++ Сборка образа где угодно

Зачем?++ Единое окружение везде

++ Ориентирован на DevOps

++ Никаких правок на горячую в коде production

++ Сборка образа где угодно

Зачем?++ Единое окружение везде

++ Ориентирован на DevOps

++ Никаких правок на горячую в коде production

++ Простота отката

++ Сборка образа где угодно

Оркестрация?

++ Kubernetes

Оркестрация?

++ Kubernetes

++ Rancher

Оркестрация?

++ Kubernetes

++ Rancher

++ Swarm

Оркестрация?

Kubernetes

Kubernetes++ By Google

Kubernetes++ By Google

++ Хорош для большого количества хостов

Kubernetes++ By Google

++ Хорош для большого количества хостов

++ Сложность

Rancher

Rancher++ Функциональный web-интерфейс

Rancher++ Функциональный web-интерфейс

++ Работает с другими оркестрациями

Rancher++ Функциональный web-интерфейс

++ Работает с другими оркестрациями

++ Относительно молодой

Swarm

Swarm++ Идет в комплекте с Docker

Swarm++ Идет в комплекте с Docker

++ Самый легкий из всех альтернатив

Swarm++ Идет в комплекте с Docker

++ Самый легкий из всех альтернатив

++ Прост в использовании

В поисках серебряной пули

В поисках серебряной пули++ Хочется прозрачности

В поисках серебряной пули++ Хочется прозрачности

++ Простые вещи дешевле поддерживать

В поисках серебряной пули++ Хочется прозрачности

++ Простые вещи дешевле поддерживать

++ Ещё одна технологическая прослойка

В поисках серебряной пули++ Хочется прозрачности

++ Простые вещи дешевле поддерживать

++ Ещё одна технологическая прослойка

++ Вероятность вернуться к прошлой инфраструктуре

В поисках серебряной пули++ Хочется прозрачности

++ Простые вещи дешевле поддерживать

++ Ещё одна технологическая прослойка

++ Вероятность вернуться к прошлой инфраструктуре

++ Время, время, время…

Docker – это же просто!

Docker – это же просто!++ docker build

Docker – это же просто!++ docker build

++ docker-compose

Docker – это же просто!++ docker build

++ docker-compose

++ BASH объединяет <3

Docker – это же просто!++ docker build

++ docker-compose

++ profit!

++ BASH объединяет <3

Dockerfile – сердце контейнера

Dockerfile – сердце контейнера++ Простой набор команд

Dockerfile – сердце контейнера++ Простой набор команд

++ RUN

Dockerfile – сердце контейнера++ Простой набор команд

++ RUN

++ COPY

Dockerfile – сердце контейнера++ Простой набор команд

++ RUN

++ COPY

++ ENV

Dockerfile – сердце контейнера++ Простой набор команд

++ RUN

++ COPY

++ ENV

++ To be continued...

Проблемы? Конечно!

Проблемы? Конечно!++ Root по умолчанию

Проблемы? Конечно!++ Root по умолчанию

++ Наследуется от одного образа

Проблемы? Конечно!++ Root по умолчанию

++ Наследуется от одного образа

++ Слишком толсто – если плодить слои

Проблемы? Конечно!++ Root по умолчанию

++ Наследуется от одного образа

++ Слишком толсто – если плодить слои

++ COPY всегда root

Проблемы? Конечно!++ Root по умолчанию

++ Наследуется от одного образа

++ Слишком толсто – если плодить слои

++ COPY всегда root

++ COPY в конце или “прощай, кэш”

Контейнерный root

Контейнерный root++ Root в контейнере = root на host-машине

++ Создаваемые файлы тоже root

Контейнерный root++ Root в контейнере = root на host-машине

++ Создаваемые файлы тоже root

Контейнерный root++ Root в контейнере = root на host-машине

++ Процесс может не встать из-под root

++ Создаваемые файлы тоже root

Контейнерный root++ Root в контейнере = root на host-машине

++ Процесс может не встать из-под root

++ Non-root – наш выбор

Linux capabilities по умолчанию

Linux capabilities по умолчанию++ chown

++ dac_override

++ fowner

++ fsetid

++ kill

++ setgid

++ setuid

++ setpcap

++ net_bind_service

++ net_raw

++ sys_chroot

++ mknod

++ audit_write

++ setfcap

++ man capabilities(7)

Добавляя безопасности

Добавляя безопасности++ --cap-add & --cap-drop для управления

Добавляя безопасности++ --cap-add & --cap-drop для управления

++ --cap-drop=all, когда это возможно

Добавляя безопасности++ --cap-add & --cap-drop для управления

++ --cap-drop=all, когда это возможно

++ Никаких --privileged

А как же stateful?

А как же stateful?++ Проблем нет только у stateless

А как же stateful?++ Проблем нет только у stateless

++ Простой путь – общие папки

А как же stateful?++ Проблем нет только у stateless

++ Простой путь – общие папки

++ Более сложный – etcd, consul, redis

А как же stateful?++ Проблем нет только у stateless

++ Простой путь – общие папки

++ Более сложный – etcd, consul, redis

++ Комбо – забираем состояние с мастер-ноды

Разделяй и используй

Разделяй и используй++ Общие папки на host-машине

Разделяй и используй++ Общие папки на host-машине

++ VOLUME внутри контейнера

Проблема записи

Проблема записи++ Неразбериха с правами на файлы

Проблема записи++ Неразбериха с правами на файлы

++ ARG USER_ID=1000 for the rescue

Проблема записи++ Неразбериха с правами на файлы

++ ARG USER_ID=1000 for the rescue

++ docker build --build-arg USER_ID="$(id -u)"

User namespaces

User namespaces++ Появились с версией 1.10

User namespaces++ Появились с версией 1.10++ Root контейнера = non uid-0 на host-машине

User namespaces++ Появились с версией 1.10++ Root контейнера = non uid-0 на host-машине++ По умолчанию отключено

User namespaces++ Появились с версией 1.10++ Root контейнера = non uid-0 на host-машине++ По умолчанию отключено++ --userns-remap в опциях запуска демона

А сети такие разные

А сети такие разные++ Bridge

А сети такие разные++ Bridge

++ Host

А сети такие разные++ Bridge

++ Host

++ Overlay

А сети такие разные++ Bridge

++ Host

++ Overlay

++ Macvlan

А сети такие разные++ Bridge

++ Host

++ Overlay

++ Macvlan

++ None

Network mode: bridge

Network mode: bridge++ На самом деле NAT

Network mode: bridge++ На самом деле NAT

++ Отдельный локальный IP для контейнера

Network mode: bridge++ На самом деле NAT

++ Отдельный локальный IP для контейнера

++ Изоляция порта внутри контейнера

Network mode: bridge++ На самом деле NAT

++ Отдельный локальный IP для контейнера

++ Изоляция порта внутри контейнера

++ Суёт свой хвост в iptables – админы недовольны

Network mode: host

Network mode: host++ Сеть хост-машины как есть в контейнере

Network mode: host++ Сеть хост-машины как есть в контейнере

++ Host port = container port

Network mode: host++ Сеть хост-машины как есть в контейнере

++ Host port = container port

++ Свобода iptables от вмешательств Docker

Network mode: host++ Сеть хост-машины как есть в контейнере

++ Host port = container port

++ Свобода iptables от вмешательств Docker

++ Наш выбор!

Network mode: overlay

Network mode: overlay++ Multi-host сеть прямо из коробки

Network mode: overlay++ Multi-host сеть прямо из коробки

++ Swarm mode (1.12+) или кастомная настройка кластера

Network mode: overlay++ Multi-host сеть прямо из коробки

++ Swarm mode (1.12+) или кастомная настройка кластера

++ Пока что всё ещё сыроват

Network mode: macvlan

Network mode: macvlan++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+

Network mode: macvlan++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+

++ Только одна сеть на сетевой интерфейс

Network mode: macvlan++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+

++ Только одна сеть на сетевой интерфейс

++ Каждому контейнеру уникальный MAC

Network mode: macvlan++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+

++ Только одна сеть на сетевой интерфейс

++ Каждому контейнеру уникальный MAC

++ Прямой доступ к другим контейнерам, минуя gateway

Network mode: macvlan++ Свежачок с 1.12, kernel v3.9–3.19 and 4.0+

++ Только одна сеть на сетевой интерфейс

++ Нет доступа из контейнера к хост-машине по IP

++ Каждому контейнеру уникальный MAC

++ Прямой доступ к другим контейнерам, минуя gateway

Network mode: none

Network mode: none++ Нет сети – нет проблем!

Network mode: none++ Нет сети – нет проблем!

++ Лучший вариант – если сеть не нужна

Limit everything

Limit everything++ CPU: --cpu-shares, --cpuset-cpus

Limit everything++ CPU: --cpu-shares, --cpuset-cpus

++ Memory: --memory, --memory-reservation

Limit everything++ CPU: --cpu-shares, --cpuset-cpus

++ Memory: --memory, --memory-reservation

++ Swap: --memory-swap, --memory-swappiness

Limit everything++ CPU: --cpu-shares, --cpuset-cpus

++ Memory: --memory, --memory-reservation

++ Swap: --memory-swap, --memory-swappiness

++ Storage: --device-read-bps, --device-write-bps

Limit everything++ CPU: --cpu-shares, --cpuset-cpus

++ Memory: --memory, --memory-reservation

++ Swap: --memory-swap, --memory-swappiness

++ Storage: --device-read-bps, --device-write-bps

++ И это далеко не всё

Собираем всё вместе

Собираем всё вместе++ Динамический docker-compose.yml

Собираем всё вместе++ Динамический docker-compose.yml

++ Одна сущность контейнера – один YAML template

Собираем всё вместе++ Динамический docker-compose.yml

++ Одна сущность контейнера – один YAML template

++ Множим контейнеры через генератор конфига

Собираем всё вместе++ Динамический docker-compose.yml

++ Одна сущность контейнера – один YAML template

++ Множим контейнеры через генератор конфига

++ scale bee=10 ant=1 goqueue=1

Шаблонизируем

Шаблонизируем++ Секция docker-compose как шаблон

Шаблонизируем++ Секция docker-compose как шаблон

++ Есть %ЗАМЕНЯЕМЫЕ% значения

Шаблонизируем++ Секция docker-compose как шаблон

++ Есть %ЗАМЕНЯЕМЫЕ% значения

++ А ещё переменные окружения

Шаблонизируем++ Секция docker-compose как шаблон

++ Есть %ЗАМЕНЯЕМЫЕ% значения

++ А ещё переменные окружения

++ Все константы и настройки – env.sh

Шаблонизируем++ Секция docker-compose как шаблон

++ Есть %ЗАМЕНЯЕМЫЕ% значения

++ А ещё переменные окружения

++ Все константы и настройки – env.sh

++ Сборка всех шаблонов в один на чистом BASH

Шаблон муравья

Шаблон муравья++ %SEQUENCE% – номер контейнера

Шаблон муравья++ %SEQUENCE% – номер контейнера

++ ${VAR} – окружение из env.sh

Шаблон муравья++ %SEQUENCE% – номер контейнера

++ ${VAR} – окружение из env.sh

++ export BEE_PORT=${BEE_PORT:-7089}

Деплой на сервер

Деплой на сервер++ Забираем свежий код из git

Деплой на сервер++ Забираем свежий код из git

++ Генерируем docker-compose.yml по окружению

Деплой на сервер++ Забираем свежий код из git

++ Генерируем docker-compose.yml по окружению

++ Собираем все образы

Деплой на сервер++ Забираем свежий код из git

++ Генерируем docker-compose.yml по окружению

++ Собираем все образы

++ Запускаем контейнеры – docker-compose --no-build up

А если несколько?

А если несколько?++ Сервера, окружения, scale – cluster.yml

А если несколько?++ Сервера, окружения, scale – cluster.yml

Выкатка на ферму

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

++ Запуск deploy-скрипта на всех выбранных нодах

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

++ Запуск deploy-скрипта на всех выбранных нодах

++ И всё это одновременно на всех нодах

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

++ Запуск deploy-скрипта на всех выбранных нодах

++ И всё это одновременно на всех нодах

++ Снова BASH: background processes & wait

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

++ Запуск deploy-скрипта на всех выбранных нодах

++ И всё это одновременно на всех нодах

++ Снова BASH: background processes & wait

++ Success or fail? Шлем в slack

Выкатка на ферму++ grep production cluster.yml | cut -d: -f1

++ Запуск deploy-скрипта на всех выбранных нодах

++ И всё это одновременно на всех нодах

++ Снова BASH: background processes & wait

++ Success or fail? Шлем в slack

В сухом остатке

В сухом остатке++ 50 человеко-часов на написание системы

В сухом остатке

++ Полная миграция за 150 человеко-часов

++ 50 человеко-часов на написание системы

В сухом остатке

++ Полная миграция за 150 человеко-часов

++ 500 строк BASH'а в 5-ти файлах на управление

++ 50 человеко-часов на написание системы

В сухом остатке

++ Полная миграция за 150 человеко-часов

++ 500 строк BASH'а в 5-ти файлах на управление

++ Масштабирование в одном месте

++ 50 человеко-часов на написание системы

В сухом остатке

++ Полная миграция за 150 человеко-часов

++ 500 строк BASH'а в 5-ти файлах на управление

++ Масштабирование в одном месте

++ Автоматизация настройки dev-окружения

++ 50 человеко-часов на написание системы

Было Стало

++ 8 мощных серверов ++ 24 дешевые машинки

Было Стало

++ 8 мощных серверов ++ 24 дешевые машинки

++ Chef, monit, Centos 6 ++ Ubuntu 16 LTS (4.4) <3 Docker

Было Стало

++ 8 мощных серверов ++ 24 дешевые машинки

++ Chef, monit, Centos 6 ++ Ubuntu 16 LTS (4.4) <3 Docker

++ 2 часа боли при деплое ++ 10 минут радости при деплое

Было Стало

++ 8 мощных серверов ++ 24 дешевые машинки

++ Chef, monit, Centos 6 ++ Ubuntu 16 LTS (4.4) <3 Docker

++ 2 часа боли при деплое ++ 10 минут радости при деплое

++ DevOps настраивают окружение ++ Developers управляют окружением

Было Стало

++ 8 мощных серверов ++ 24 дешевые машинки

++ Chef, monit, Centos 6 ++ Ubuntu 16 LTS (4.4) <3 Docker

++ 2 часа боли при деплое ++ 10 минут радости при деплое

++ DevOps настраивают окружение ++ Developers управляют окружением

++ Ручной scale процессов ++ Scale по необходимости деплоем

Было Стало

dmitrii@kuzmenkov.me

dmitrykuzmenkov

Вопросы? dmitrii@kuzmenkov.me

dmitrykuzmenkov