- PVSM.RU - https://www.pvsm.ru -
В данной статье речь пойдет об истории успеха воображаемого новостного портала, счастливым владельцем которого являетесь вы. К счастью, вы уже храните код проекта на GitLab.com и знаете, что для тестирования можно использовать GitLab CI [1].
Теперь вам интересно, можно ли пойти дальше и использовать CI еще и для развертывания проекта, и если да, то какие возможности при этом открываются.
Чтобы не привязываться к какой-либо конкретной технологии, предположим, что ваше приложение является простым набором HTML-файлов, никакого выполнения кода на сервере, никакой компиляции JS assets. Деплоить будем на Amazon S3 [2].
У автора нет цели дать рецепты для конкретной технологии в этой статье. Наоборот, примеры кода максимально примитивны, чтобы слишком на них не зацикливаться. Смысл в том чтобы вы посмотрели на фичи и принципы работы GitLab CI в действии, а потом применили их для вашей технологии.
Начнем с начала: в вашем вымышленном приложении пока еще нет поддержки CI.
Развертывание: в данном примере результатом развертывания должно быть появление набора HTML-файлов в вашем бакетe (bucket) S3, который уже настроен для хостинга статических вебсайтов [3]).
Добиться этого можно множеством различных способов. Мы будем использовать библиотеку
awscli [4] от Amazon.
Полностью команда развертывания выглядит следующим образом:
aws s3 cp ./ s3://yourbucket/ --recursive --exclude "*" --include "*.html"
Пуш кода в репозиторий и развертывание — это два разных процесса
Важно: эта команда ожидает [5], что вы передадите ей переменные окружения AWS_ACCESS_KEY_ID
и AWS_SECRET_ACCESS_KEY
. Также от вас может потребоваться указать AWS_DEFAULT_REGION
.
Попробуем автоматизировать этот процесс с использованием GitLab CI.
При работе с GitLab используются все те же команды, что и при работе на локальном терминале. Вы можете настроить GitLab CI в соответствии с вашими требованиями так же, как вы настраиваете ваш локальный терминал. Все команды, которые можно выполнить на вашем компьютере, можно выполнить и в GitLab, передав их в CI. Просто добавьте ваш скрипт в файл .gitlab-ci.yml
и сделайте пуш — вот и все, CI запускает задачу (job) и выполняет ваши команды.
Добавим деталей в нашу историю: ваш веб-сайт небольшой — 20-30 посетителей в день, а в репозитории есть только одна ветка — master
.
Начнем с того, что добавим задачу с командой aws в .gitlab-ci.yml
:
deploy:
script: aws s3 cp ./ s3://yourbucket/ --recursive --exclude "*" --include "*.html"
Неудача:
Нам нужно удостовериться в наличии исполняемого файла aws
. Для установки awscli
требуется pip
— инструмент для установки пакетов Python. Укажем образ Docker с предустановленным Python, в котором также должен содержаться pip
:
deploy:
image: python:latest
script:
- pip install awscli
- aws s3 cp ./ s3://yourbucket/ --recursive --exclude "*" --include "*.html"
При пуше на GitLab код автоматически развертывается с помощью CI
Установка awscli
увеличивает время выполнения задачи, но сейчас нас это не особенно волнует. Если вы все же хотите ускорить процесс, можете поискать образ Docker [6] с предустановленным awscli
, или же создать такой своими силами.
Также, не стоит забывать о переменных окружения, полученных из AWS Console [7]:
variables:
AWS_ACCESS_KEY_ID: "AKIAIOSFODNN7EXAMPLE"
AWS_SECRET_ACCESS_KEY: “wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY”
deploy:
image: python:latest
script:
- pip install awscli
- aws s3 cp ./ s3://yourbucket/ --recursive --exclude "*" --include "*.html"
Должно сработать, однако держать секретные ключи в открытом виде (даже в приватном репозитории) — не самая лучшая идея. Посмотрим, что с этим можно сделать.
В GitLab есть специальный раздел для секретных переменных: Settings > Variables
Все данные, помещенные в этот раздел станут переменными окружения. Доступ к этому разделу есть только у администратора проекта.
Раздел variables
можно удалить из настроек CI, но лучше давайте воспользуемся им для другой цели.
С увеличением размера файла конфигурации становится удобнее хранить некоторые параметры в его начале в качестве переменных. Такой подход особенно актуален в случае, когда эти параметры используются в нескольких местах. Хоть в нашем случае до такого пока что не дошло, в демонстрационных целях создадим переменную [8] для названия бакета S3:
variables:
S3_BUCKET_NAME: "yourbucket"
deploy:
image: python:latest
script:
- pip install awscli
- aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude "*" --include "*.html"
Сборка успешна:
Тем временем посещаемость вашего сайта повысилась, и вы наняли разработчика, чтобы он вам помогал. Теперь у вас есть команда. Посмотрим как работа в команде влияет на рабочий процесс.
Теперь в одном и том же репозитории работают два человека, и использовать ветку master
для разработки более не целесообразно. Поэтому вы принимаете решение использовать различные ветки для разработки новых фич и написания статей и мержить их в master
по мере готовности.
Проблема в том, что при текущей настройке CI не поддерживает работу с ветками — при пуше в любую ветку на GitLab происходит развертывание текущего состояния master
на S3.
К счастью, это легко исправить — просто добавьте only: master
в задачу deploy
.
Мы хотим избежать развертывания каждой ветки на сайте
С другой стороны, было бы неплохо иметь возможность предпросмотра изменений, внесенных из веток для выделенной функциональности (feature-веток).
Патрик (разработчик, которого вы недавно наняли) напоминает вам, что существует такая функциональность, как
GitLab Pages [9]. Как раз то, что нужно — место для предпросмотра новых изменений.
Для размещения вебсайта на GitLab Pages [10] ваша конфигурация CI должна удовлетворять трем простым требованиям:
pages
artifacts
, а в нем содержаться папка public
public
должно находиться все, что вы хотите разместить на сайтеСодержимое папки public будет размещено по адресу http://<username>.gitlab.io/<projectname>/
После добавления кода из примера для сайтов на чистом HTML [11] файл настройки CI выглядит следующим образом:
variables:
S3_BUCKET_NAME: "yourbucket"
deploy:
image: python:latest
script:
- pip install awscli
- aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude "*" --include "*.html"
only:
- master
pages:
image: alpine:latest
script:
- mkdir -p ./public
- cp ./*.html ./public/
artifacts:
paths:
- public
except:
- master
Всего в нем содержатся две задачи: одна (deploy
) проводит развертывание сайта на S3 для ваших читателей, а другая (pages
) на GitLab Pages. Назовем их соответственно "Production environment" и "Staging environment".
Развертывание всех веток, кроме master, будет проводиться на GitLab Pages
GitLab поддерживает работу со средами развертывания [12]. Все, что вам нужно сделать, это назначить соответствующую среду для каждой задачи развертывания:
variables:
S3_BUCKET_NAME: "yourbucket"
deploy to production:
environment: production
image: python:latest
script:
- pip install awscli
- aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude "*" --include "*.html"
only:
- master
pages:
image: alpine:latest
environment: staging
script:
- mkdir -p ./public
- cp ./*.html ./public/
artifacts:
paths:
- public
except:
- master
GitLab отслеживает все ваши процессы развертывания, так что вы всегда можете увидеть, что в текущий момент развертывается на ваших серверах:
Также, GitLab хранит полную историю всех развертываний для каждой среды:
Итак, мы оптимизировали и настроили все, что только могли, и готовы к новым вызовам, которые не заставят себя долго ждать.
Опять. Это опять произошло. Стоило вам только запушить свою feature-ветку для превью, как спустя минуту Патрик сделал то же самое и тем самым перезаписал содержимое staging. #$@! Третий раз за сегодня!
Идея! Используем Slack для оповещений о развертываниях, чтобы никто не пушил новые изменения, пока старые не закончили развертываться.
Настроить оповещения Slack несложно [13]. Надо лишь взять из Slack URL входящего вебхука [14]…
… и передать его в Settings > Services > Slack вместе с вашим логином Slack:
Поскольку вы хотите получать уведомления только о развертываниях, в показанных выше настройках можно убрать галочки на всех пунктах, кроме “Build”. Вот и все, теперь вы будете получать оповещения о каждом развертывании:
Со временем ваш сайт стал очень популярным, а ваша команда выросла с двух до восьми человек. Разработка происходит параллельно, и людям все чаще приходится ждать в очереди для превью на Staging. Подход “Проводите развертывание каждой ветки на Staging” больше не работает.
Пришло время вновь модифицировать рабочий процесс. Вы и ваша команда пришли к соглашению, что для выкатывания изменений на staging-сервер нужно сначала сделать мерж этих изменений в ветку “staging”.
Для добавления этой функциональности нужно внести лишь небольшие изменения в файл .gitlab-ci.yml
:
except:
- master
становится
only:
- staging
Разработчики проводят мерж своих feature-веток перед превью на Staging
Само собой, при таком подходе на мерж тратятся дополнительное время и силы, но все в команде согласны, что это лучше, чем ждать в очереди.
Невозможно все контролировать, и неприятности имеют свойство случаться. К примеру, кто-то неправильно смержил ветки и запушил результат прямо в production как раз когда ваш сайт находился в топе HackerNews. В результате тысячи человек увидели кривую версию сайта вместо вашей шикарной главной страницы.
К счастью, нашелся человек, который знал про кнопку Rollback, так что уже через минуту после обнаружения проблемы сайт принял прежний вид.
Rollback перезапускает более раннюю задачу, порожденную в прошлом каким-то другим коммитом
Чтобы избежать подобного в дальнейшем, вы решили отключить автоматическое развертывание в production и перейти на развертывание вручную. Для этого в задачу нужно добавить when: manual
.
Для того, чтобы запустить развертывание вручную, перейдите на вкладку Pipelines > Builds и нажмите на вот эту кнопку:
И вот ваша компания превратилась в корпорацию. Над сайтом работают сотни человек, и некоторые из предыдущих рабочих практик уже не очень подходят к новым обстоятельствам.
Следующим логическим шагом является добавление возможности развертывания временного инстанса приложения каждой feature-ветки для ревью.
В нашем случае для этого надо настроить еще один бакет S3, с той лишь разницей, что в этом случае содержимое сайта копируется в “папку” с названием ветки. Поэтому URL выглядит следующим образом:
http://<REVIEW_S3_BUCKET_NAME>.s3-website-us-east-1.amazonaws.com/<branchname>/
А так будет выглядеть код, замещающий задачу pages
:
review apps:
variables:
S3_BUCKET_NAME: "reviewbucket"
image: python:latest
environment: review
script:
- pip install awscli
- mkdir -p ./$CI_BUILD_REF_NAME
- cp ./*.html ./$CI_BUILD_REF_NAME/
- aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude "*" --include "*.html"
Стоит объяснить откуда у нас появилась переменная $CI_BUILD_REF_NAME
— из списка предопределенных переменных окружения GitLab [15], которые вы можете использовать для любой своей задачи.
Обратите внимание на то, что переменная S3_BUCKET_NAME
определена внутри задачи — таким образом можно переписывать определения более высокого уровня.
Визуальная интерпретация такой конфигурации:
Технические детали реализации такого подхода сильно разнятся в зависимости от используемых в вашем стеке технологий и от того, как устроен ваш процесс развертывания, что выходит за рамки этой статьи.
Реальные проекты, как правило, значительно сложнее, чем наш пример с сайтом на статическом HTML. К примеру, поскольку инстансы временные, это сильно усложняет их автоматическую загрузку со всеми требуемыми сервисами и софтом “на лету”. Однако это выполнимо, особенно, если вы используете Docker или хотя бы Chef или Ansible.
Про развертывание при помощи Docker будет рассказано в другой статье. Честно говоря, я чувствую себя немного виноватым за то, что упростил процесс развартывания до простого копирования HTML-файлов, совершенно упуская более хардкорные сценарии. Если вам это интересно, рекомендую почитать статью "Building an Elixir Release into a Docker image using GitLab CI" [16].
А пока что давайте обсудим еще одну, последнюю проблему.
В реальности мы не ограничены S3 и GitLab Pages; приложения разворачиваются на различные сервисы.
Более того, в какой-то момент вы можете решить переехать на другую платформу, а для этого вам нужно будет переписать все скрипты развертывания. В такой ситуации использование gem’а dpl
сильно упрощает жизнь.
В приведенных в этой статье примерах мы использовали awscli
в качестве инструмента для доставки кода на сервис Amazon S3. На самом деле, неважно, какой инструмент вы используете и куда вы доставляете код — принцип остается тот же: запускается команда с определенными параметрами и в нее каким-то образом передается секретный ключ для идентификации.
Инструмент для развертывания dbl
придерживается этого принципа и предоставляет унифицированный интерфейс для определенного списка плагинов (providers) [17], предназначенных для развертывания вашего кода на разных хостинговых площадках.
Задача для развертывания в production с использованием dpl будет выглядеть вот так:
variables:
S3_BUCKET_NAME: "yourbucket"
deploy to production:
environment: production
image: ruby:latest
script:
- gem install dpl
- dpl --provider=s3 --bucket=$S3_BUCKET_NAME
only:
- master
Так что если вы проводите развертывание на различные хостинговые площадки или часто меняете целевые платформы, подумайте над использованием dpl
в скриптах развертывания — это способствует их единообразию.
Автор: Softmart
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/open-source/190125
Ссылки в тексте:
[1] для тестирования можно использовать GitLab CI: https://about.gitlab.com/2016/07/29/the-basics-of-gitlab-ci/#run-our-first-test-inside-ci
[2] Amazon S3: https://aws.amazon.com/s3/
[3] хостинга статических вебсайтов: http://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html?shortFooter=true
[4] awscli: http://docs.aws.amazon.com/cli/latest/reference/s3/cp.html#examples
[5] ожидает: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence
[6] поискать образ Docker: https://hub.docker.com/explore/
[7] AWS Console: https://console.aws.amazon.com/
[8] переменную: http://docs.gitlab.com/ee/ci/variables/README.html
[9] GitLab Pages: http://pages.gitlab.io
[10] размещения вебсайта на GitLab Pages: https://about.gitlab.com/2016/04/07/gitlab-pages-setup/
[11] примера для сайтов на чистом HTML: https://gitlab.com/pages/plain-html/blob/master/.gitlab-ci.yml
[12] поддерживает работу со средами развертывания: http://docs.gitlab.com/ee/ci/environments.html#environments
[13] несложно: http://docs.gitlab.com/ce/project_services/slack.html
[14] входящего вебхука: https://api.slack.com/incoming-webhooks
[15] предопределенных переменных окружения GitLab: http://docs.gitlab.com/ce/ci/variables/README.html#predefined-variables-environment-variables
[16] "Building an Elixir Release into a Docker image using GitLab CI": https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/
[17] определенного списка плагинов (providers): https://github.com/travis-ci/dpl#supported-providers
[18] Источник: https://habrahabr.ru/post/310502/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.