Continuous delivery, Continuous integration, Docker при «многоверсионном» приложении. Как организовать?
Мы разрабатываем бэкэнды для приложений в социальных сетях.
1) Хотим организовать нормальный процесс деплоя приложений. Основная проблема в том, что приложение выкладывается на разные платформы в разных версиях (например разработали новый функционал, запустили тестировать на продакшне на вконтакте), параллельно - какой-то другой функционал может тестироваться на другой платформе, т.е. это разные версии одного и того же кода, где-то он мог уйти дальше, где-то нет.
Сейчас мы используем gitlab, docker, ansible для деплоя приложений, в таск ansible передается айди платформы, на которой нужно развернуть приложение и ветка репозитория - из которой нужно его забрать. Ansible обновляет докер (сам образ собирается вручную), ansible забирает из гита исходный код, грузит на сервер, в контейнеры исходники пробрасываются через volume.
Хотим настроить полный цикл через gitlab+pipelines. Вопрос - как грамотно собирать разные версии под разные платформы? Решение в лоб - завести в гите ветки на каждую платформу (release_vk, release_..), в CI будет собираться образ сразу с исходным кодом, помечаться тегом платформы, деплоится по тегу на сервера(latest_vk, latest_...).
Не нравится, что в итоге заводится куча тегов, веток, может есть альтернативное решение для такой задачи?
2) Разные версии приложений запускаются на одних и тех-же серверах, т.е. запросы к api идут dns-балансировкой, стоит nginx на фронте, который раскидывает запросы уже на остальные контейнеры, фактически на другой nginx, который уже рулит контейнером с php.
Схема кажется немного избыточна nginx->nginx->php, в итоге на сервере дофигища разных процессов, особенно nginx.
Общий вопрос - как при таких бизнес-процессах можно "оптимизировать" схему работы. Кажется, что должно быть какое-то более красивое решение для всего.
Решение в лоб - завести в гите ветки на каждую платформу (release_vk, release_..), в CI будет собираться образ сразу с исходным кодом, помечаться тегом платформы, деплоится по тегу на сервера(latest_vk, latest_...).
На мой взгляд - самое правильное решение, вопрос только в синхронизации функционала основного кода и веток платформ - придется постоянно мерджить или ребэйсить.
Либо, как вариант - форки от основного проекта. Отдельный репозиторий под каждую платформу наследуемый от основного.
2) Разные версии приложений запускаются на одних и тех-же серверах, т.е. запросы к api идут dns-балансировкой, стоит nginx на фронте, который раскидывает запросы уже на остальные контейнеры, фактически на другой nginx, который уже рулит контейнером с php.
Схема кажется немного избыточна nginx->nginx->php, в итоге на сервере дофигища разных процессов, особенно nginx.
В идеологии докера это правильное решение. К тому же легко масштабируемое - при необходимости можно каждую версию вынести на отдельный сервер.
Подскажите, а статика у вас тоже проксируется? Или отдается непосредственно первым nginx?
Общий вопрос - как при таких бизнес-процессах можно "оптимизировать" схему работы. Кажется, что должно быть какое-то более красивое решение для всего.
А что именно хочется прооптимизировать? Архитектуру? Если да, то в понятиях докера она оптимальна.
Если скорость работы, масштабируемость, потребляемые ресурсы, и т.д., то нужно каждый случай рассматривать конкретно.
В rails можно обойтись без второго nginx (пользоваться встроенной пумой, например), в PHP встроенный сервер (мне по крайней мере) не удалось адекватно использовать, поэтому так же ставлю nginx + php-fpm.
Можно не проксировать статику, а отдавать самим прокси (если статики много) или внутренний nginx заменить на что-то более легкое. Так же посмотреть базовые контейнеры - возможно стоит использовать Alpine в базе каких-то контейнеров.
Если проксируете своей сборкой nginx - смотрите в сторону jwilder/nginx-proxy - там все автоматизировано.
Docker-compose - думаю, что используете, но если нет, то стоит.
И лучше всего, конечно, сами контейнеры по максимуму универсально использовать - если билдите свои контейнеры, то делать свой универсальный контейнер (того же nginx или php) и использовать его (вместо множества отдельно собираемых одинаковых) - в этом случае сборки будут использовать один образ вместо кучи разных, а в случае необходимости изменения контейнера - наследовать от него частные и вносить в него уже конкретные изменения.
Ну и т. д.
Не нравится, что в итоге заводится куча тегов, веток, может есть альтернативное решение для такой задачи?
На самом деле это оптимальное решение. У вас создается релизная ветка в которую в случае проблем именно на этой платформе будут вливаться фиксы, не мешающие другим. Далее когда релизный образ оттестирован и дан зеленый свет - они размазывается по проду. То что тегов много - да какая разница?)) У вас есть возможность получить состояние любой сборки.
Схема кажется немного избыточна nginx->nginx->php, в итоге на сервере дофигища разных процессов, особенно nginx.
Тут все зависит от того, можно ли отдавать клиенту доступ на прямую к nginx2. Если нельзя - ваша схема вполне норм. Если же можно - тогда стоит это делать, смотрите в сторону своего балансировщика, который будет отдавать клиенту сервер, который А - жив, Б - минимально нагружен и штук типа consul.
ansible забирает из гита исходный код, грузит на сервер, в контейнеры исходники пробрасываются через volume.
Зачем? Контейнер как бы иммутабельный и все такое. Если у вас там кучка статики подсасывается не под git - смотрите в сторону mogilefs и т.д. Безусловно, для разработки volume - самое оно, но для прода - ну такое..., должна быть веская причина.