Comments 39
С инструкцией по установке GitLab CI Runner можно ознакомиться на сайте docs.docker.com.
Скажите, используете ли вы проверку кода (CodeSniffer)? Как вы считаете, уместно ли проверять код именно тут. Ведь на сколько я понимаю, если код не прошел проверку, то его просто вообще нельзя запушить на сервер.
Проверку на coding style можно было бы запускать до этапа build и после этапа deps. Параллельно с phpunit, например, было бы самое оно. Ну и этап можно было бы переименовать: вместо test сделать qa, например. Вообще ещё много чего можно добавить в pipeline! Например, этапа lint нет. Ещё нужно проверять а запустятся ли контейнеры после сборки до того, как их выложим на удалённый сервер и как они будут работать (вот тут я не знаю каким инструментом можно воспользоваться, кстати). Может быть ещё что-нибудь.
Ещё я не согласен с тем, что непрошедший проверку на coding style код, не может быть запушен на сервер! Если такую проверку и вводить, то этот код таки будет запушен, но результат работы не дойдёт до тестового сайта разработчика (не говоря уже про staging и production), что не позволит сдать результат работы. И если такая проверка (как и phpunit-тестирование, кстати) не позволяет выкладывать код на удалённый сервер, разработчик должен будет исправить недочёты, объединить коммиты и запушить --force свой код ещё раз.
build — создаем контейнеры и пушим в Registry
deps — используем созданные контейнеры из Registry
test — используем созданные контейнеры из Registry
Кстати, ведь для тестов вероятно нужны будут зависимости, но так как это другая джоба, то зависимостей не этапе теста нет. Тут наверное нужно объеденить deps и test в одну джобу?
На самом деле в скелете приложения задача deps:php-composer не особо и нужна. Она заполняет кэш composer, а использует этот кэш только задача test:phpunit. Задача test:phpunit запускает composer require phpunit/phpunit:* --dev
что, также как и в deps, заполняет кэш composer. Я оставил deps в шаблоне "на всякий пожарный", чтобы в случае, когда параллельно с phpunit будут выполнятся какие-то другие задачи, — этот кэш не надо было наполнять в конкурентной борьбе компоузеров.
И если останется только одна задача на этапе test, то deps и test можно будет объединить. А если появится третья, например, phpcs — то весь кэш нужно будет загружать в deps так, чтобы он был доступен и для phpunit и для phpcs, т.е. объединять не нужно. Пусть пока будут разъединёнными — а потом либо надо будет удалить deps, либо на "потенциальном" этапе qa что-нибудь появится такое, что будет полезным всем.
cache:
paths:
- vendor/
А каким образом это происходит у вас? ведь наполненый кеш композера и заполненая папка vendors это все таки разные вещи. И для исполнения скриптов нужно чтоб были фалы в vendors, а не в кеше композера.
Таким образом можно закэшировать только директории внутри рабочей директории.
В Dockerfile образа для php домашняя директория composer
установлена в /composer/home
. Кэш composer
находится в /composer/home/cache
. Эта директория находится вне рабочей директории, с которой может работать GitLab Runner.
И поэтому я сначала формирую кэш composer, чтобы много раз запускать composer install
или composer require
.
Весь процесс будет работать и без кэширования этой директории. Но с кэшированием через gitlab ci runner оно просто быстрее работает. Но, вообще, я согласен про возможность "нечаянно сломать".
Вы описали так джоб, где композер инсталирует зависимости
deps:php-composer:
stage: deps
image: covex/php7.1-fpm:1.0
script:
- echo ...
- composer install --prefer-dist --no-scripts --no-autoloader --no-interaction
Но это не боевой контейнер, а «covex/php7.1-fpm:1.0», вы ведь когда будете изменять php docker image (тут) образы могут быть разные. Вы тестируете не тем образом что будет в продакшене
Это не инсталирование зависимостей, а заполнение кэша composer, чтобы этот кэш использовали следущие задачи. Кэш composer хранится в volume у gitlab-ci-runner и доступен для всех задач, которые запускаются этим runner-ом.
Окружение на этапе test, когда работает phpunit, совпадает с тем, что в production — там один и тот же образ. Но в production (да и везде внутри контейнеров, запущенных через docker-compose) — есть база данных, а на этапе test, для phpunit этой БД ещё нет.
Для юнит-тестов этой группы подключение БД не нужно, а юнит-тестов, использующих БД ещё и не существует. Наверное, эту задачу нужно будет сделать вместе с "интеграционными тестами". Например: (1) запускаем docker-compose внутри docker (2) проверяем запущены ли все контейнеры (3) наполняем БД данными для тестирования (4) запускаем тесты, использующие БД.
Вы тестируете образом «covex/php7.1-fpm:1.0», а на продакшене образ от этого файла который наследуется от «covex/php7.1-fpm:1.0».
Если вы будете менять образ для прода, вы ведь в этот же файл планируете вносить изминения, а не в базовый образ? Если так, то получается два разных образа.
Если вдруг будет нужно установить новое расширение или ещё какое-нибудь ПО внутрь образа с php, я сделаю новый образ на основе Dockerfile
для образа covex/php7.1-fpm:1.0
и буду использовать новый образ как "базовый" для проекта на всех стадиях.
Расширения php для образа на основе alpine
очень долго устанавливаются. Для создания образа я использую репозиторий на gitlab.com — там сборка образа занимает 3-4 минуты. Локально у меня на ноуте это длится в разы дольше. Если очень часто запускать docker-compose down -v
и затем docker-compose up -d
то, можно весь день только этим и заниматься =)
Локально используется файл Dockerfile-dev
— это "базовый образ" плюс включение расширения xdebug.
Но, видимо, тут какое-то недопонимание есть. Локально весь код находится на хосте. Внутри контейнера код доступен в директории /srv
. Плюс локально нужно вручную запускать phing
после запуска docker-compose up
На удалённом сервере создаётся новый образ. Это "базовый образ" плюс копирование кода в внутрь контейнера, также в папку /srv
; плюс запускается composer install
; плюс запускается phing
(для вызова cache:warmup и assets:install).
Таким образом "базовый образ" — это основа для всех окружений. От проекта к проекту основа может отличаться. Расширениями, например.
"Базовый образ" для скелета приложения — дефолтный covex/php7.1-fpm:1.0
. Для другого проекта — он может быть другим, и я его сначала подготовлю, а потом буду использовать также как дефолтный.
На этапе test базы данных не существует — там только php. БД появляется в docker-compose
после этапа build.
Основной репозиторий "скелета приложения" хранится у нас внутри GitLab. Репозиторий на GitHub — это его копия. И для репозитория на GitHub я дополнительно подключил travis-ci для тестирования "как система будет запускаться с нуля". Вот файл .travis.yml, и вот задача внутри travis.
И вот в Travis CI тесты запускатся внутри docker-compose
! Таким же самым образом можно сделать "тестирование-с-базой-данных" на этапе между build и deploy. Но это сейчас не реализовано, да.
Чтобы иметь возможность безболезненно менять историю коммитов. Ну и чтобы изменения одного разработчика никак не влияли на результат работы другого.
До docker
у нас был один репозиторий, доступный для всех разработчиков, на проект. Для деплоя на тестовый сайт проекта, мы используем ещё один "служебный и скрытый ото всех" репозиторий, в который jenkins
заливает изменения после push в ветку задачи разработчика. Вобщем, у нас Система. И эта система ломается, когда кто-то из добрых и хороших побуждений решает сделать git push --force
— приходится чистить и приводить репозитории к работоспособному виду.
А иногда разработчики правят один и тот же файл в одном и том же месте! Тут опять приходится вмешиваться, потому что и тут система оказывается сломаной =) И хорошо ещё, что репозитории находятся внутри GitLab (он у нас какой-то там совсем старой версии), так что ветки master
и production
у нас защищены от изменений.
Ещё иногда случается, что локально без изменения коллеги всё работает, а на тестовом сайте, со слитыми изменениями всех разработчиков, что-то идёт не так.
Сейчас же у разработчика есть и свобода действий с историей коммитов с одной стороны, и строгие рамки в виде ветки origin/stable
— все изменения должны идти строго после неё.
Перемудрено сильно, по-моему. Три ветки (у нас было мастер, препрод и дев) защищенные по полной, для каждой фичи или разработчика отдельная ветка, которая средствами CI/CD гитлаба и докера разворачивается на отдельный домен типа cool-feature-branch.dev.example.com, ветка препрод идёт на preprod.example.com, а мастер на example.com. Локально смотреть можно на cool-feature-branch.example.com.localhost (по дефолту, а в принципе через env переменные передаётся).
Локально — на машине разработчика разворачивается система, по возможности без необходимости ребилдить при каждом изменении исходников через монтирование volumes
Автоматическая привязка создается примерно так:
- контейнер с прокси (nginx, haproxy, ...), привязывается к 80/443/… порту хоста, слушает события докера и при наличии у стартующего контейнера специальных меток (имя домена, порт, протокол и т. п.) реконфигурирует прокси для нового контейнера. Есть минимум два готовіх решения — docker-flow и nginx-proxy. Я первое выбрал, поскольку в целом swarm используем.
- внешний днс сервер настраивается на вилд-кард для домена, типа *.dev.example.com, резолвя его на хост с контейнером прокси.
Сейчас начал писать пост о разработке микросервисной системы, в основе большинства сервисов которой на Symfony 3+ с DDD, ES и т. п… Не знаю успею ли закончить до 1 сентября, но постараюсь и этот момент отразить. Если не успею, то не знаю когда закончить смогу.
Основная проблема, внезапно, сначала придумать, а потом реализовать предметную область. Вроде придумал одну, но как-то она полезла в теорию графов внезапно. Вот сижу думаю стоит ли зарываться, реализовать "в лоб", а-ля MVP или переключиться на классические "бложики-тудушечки".
before_script:
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY")
ssh-add <очепятка?
Это работает как нужно. И я скопировал это из документации на docs.gitlab.com
deploy_dev:
stage: deploy
script:
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" > /tmp/id_rsa && chmod 600 /tmp/id_rsa && ssh-add /tmp/id_rsa
- ssh -o StrictHostKeyChecking=no -p $SSH_PORT $SSH_USER@$SSH_HOST
environment:
name: dev
only:
- dev
Непрерывная интеграция/внедрение приложения Symfony с помощью docker-compose и GitLab CI