Прямо сейчас мы пишем новые главы самоучителя!
Эта страница находится в разработке.

Показать, что уже готово

Файлы, упомянутые в главе

  • .gitlab-ci.yml

После того, как мы разобрались, как делать сборку и деплой «вручную», пора заняться автоматизацией.

Для этого предлагается простой рабочий процесс, который мы называем fast and furious. Он позволит осуществлять быструю доставку изменений в production и содержать два окружения: production и staging.

Начнем с того, что добавим сборку в CI с помощью .gitlab-ci.yml, который находится в корне проекта, и опишем там заготовки для всех стадий и общий код, обеспечивающий работу werf:

before_script:
  - type multiwerf && source <(multiwerf use 1.1 stable)
  - type werf && source <(werf ci-env gitlab --verbose)

Build:
  stage: build
  script:
    - echo "todo build"
  tags:
    - werf

Deploy to staging:
  script:
    - echo "todo deploy to staging"
  environment:
    name: staging
    url: http://staging.example.com
  only:
    - merge_requests
  when: manual

Deploy to production:
  script:
    - echo "todo deploy to production"
  environment:
    name: production
    url: http://example.com
  only:
    - master
before_script: - type multiwerf && source <(multiwerf use 1.1 stable) - type werf && source <(werf ci-env gitlab --verbose) Build: stage: build script: - echo "todo build" tags: - werf Deploy to staging: script: - echo "todo deploy to staging" environment: name: staging url: http://staging.example.com only: - merge_requests when: manual Deploy to production: script: - echo "todo deploy to production" environment: name: production url: http://example.com only: - master
Зачем используется multiwerf?

Такой сложный путь в before_script с использованием multiwerf нужен для того, чтобы не думать про обновление werf и об установке новых версий. С этой утилитой достаточно указать, что вы используете, например, werf v1.1-stable (use 1.1 stable), после чего быть в уверенности, что у вас актуальная версия werf.

Что за werf ci-env gitlab?

Практически все опции werf можно задавать переменными окружения. Команда ci-env проставляет предопределенные значения, которые будут использоваться всеми командами werf в shell-сессии, на основе переменных окружений CI:

### DOCKER CONFIG
export DOCKER_CONFIG="/tmp/werf-docker-config-832705503"
### STAGES_STORAGE
export WERF_STAGES_STORAGE="registry.example.com/werf-guided-golang/stages"
### IMAGES REPO
export WERF_IMAGES_REPO="registry.example.com/werf-guided-golang"
export WERF_IMAGES_REPO_IMPLEMENTATION="gitlab"
### TAGGING
export WERF_TAG_BY_STAGES_SIGNATURE="true"
### DEPLOY
# export WERF_ENV=""
export WERF_ADD_ANNOTATION_PROJECT_GIT="project.werf.io/git=https://lab.example.com/werf-guided-golang"
export WERF_ADD_ANNOTATION_CI_COMMIT="ci.werf.io/commit=61368705db8652555bd96e68aadfd2ac423ba263"
export WERF_ADD_ANNOTATION_GITLAB_CI_PIPELINE_URL="gitlab.ci.werf.io/pipeline-url=https://lab.example.com/werf-guided-golang/pipelines/71340"
export WERF_ADD_ANNOTATION_GITLAB_CI_JOB_URL="gitlab.ci.werf.io/job-url=https://lab.example.com/werf-guided-golang/-/jobs/184837"
### IMAGE CLEANUP POLICIES
export WERF_GIT_TAG_STRATEGY_LIMIT="10"
export WERF_GIT_TAG_STRATEGY_EXPIRY_DAYS="30"
export WERF_GIT_COMMIT_STRATEGY_LIMIT="50"
export WERF_GIT_COMMIT_STRATEGY_EXPIRY_DAYS="30"
export WERF_STAGES_SIGNATURE_STRATEGY_LIMIT="-1"
export WERF_STAGES_SIGNATURE_STRATEGY_EXPIRY_DAYS="-1"
### OTHER
export WERF_LOG_COLOR_MODE="on"
export WERF_LOG_PROJECT_DIR="1"
export WERF_ENABLE_PROCESS_EXTERMINATOR="1"
export WERF_LOG_TERMINAL_WIDTH="95"

Многие из этих переменных интуитивно понятны и содержат базовую информацию о том, где находится проект и его Registry, информацию о коммитах. В рамках статьи достаточно значений, выставляемых по умолчанию.

Подробную информацию о конфигурации ci-env можно найти в документации.

Если вы используете GitLab CI совместно с внешним Docker Registry (им может быть не только сам Docker Registry, но и Harbor, Quay или другой совместимый реестр), то в команду сборки и публикации нужно добавлять его полный адрес (включая путь внутри Registry). Как это сделать, тоже написано в документации. Кроме того, понадобится не забыть первой командой выполнить docker login.

Сборка в GitLab CI

Укажем в стадии сборки уже знакомую команду:

Build:
  stage: build
  script:
    - werf build-and-publish
Build: stage: build script: - werf build-and-publish

Теперь при коммите кода в GitLab будет происходить сборка:

Деплой в GitLab CI

Опишем деплой приложения в Kubernetes. Деплой будет осуществляться в два окружения: staging и production.

Выкат на два стенда отличается только параметрами, поэтому воспользуемся шаблонами. Начнем с базового деплоя, который потом будем кастомизировать под стенды:

.base_deploy: &base_deploy
  stage: deploy
  script:
    - werf deploy
  dependencies:
    - Build
  tags:
    - werf
.base_deploy: &base_deploy stage: deploy script: - werf deploy dependencies: - Build tags: - werf

В результате мы можем делать деплой, например, на staging с использованием базового шаблона:

Deploy to staging:
  extends: .base_deploy
  environment:
    name: staging
    url: http://staging.example.com
  only:
    - merge_requests
  when: manual
Deploy to staging: extends: .base_deploy environment: name: staging url: http://staging.example.com only: - merge_requests when: manual

Аналогичным образом — настраиваем production-окружение.

После описания стадий выката при создании Merge Request будет доступна кнопка «Deploy» для Staging контура:

Посмотреть статус выполнения пайплайна можно в интерфейсе GitLab (CI / CD → Pipelines):

Очистка образов

При активной разработке в скором времени образы начнут занимать все больше и больше места в нашем registry. Если ничего не предпринять, то registry может разрастись до неприличных размеров. Для решения этой проблемы в werf реализован эффективный многоуровневый алгоритм очистки образов.

Автоматическая очистка реестра контейнеров в werf работает по определенным правилам: политикам очистки. Эти политики определяют, какие образы можно удалять, а какие — нет.

Существуют 3 основные политики очистки:

По веткам

werf удаляет образ из реестра в случае отсутствия в Git-репозитории соответствующей ветки. Образ никогда не удаляется, пока существует соответствующая ветка в Git-репозитории.

По коммитам

werf удаляет образ из реестра в случае отсутствия в Git-репозитории соответствующего коммита. Для остальных образов применяется следующая политика:

Оставлять образы в registry не старше указанного количества дней с момента их публикации или же оставлять в registry не более, чем указанное количество образов.

По тегам

werf удаляет образ из registry в случае отсутствия в Git-репозитории соответствующего тега. Для остальных образов применяется политика, аналогичная случаю с коммитами, что описан выше.

При этом из registry никогда не удаляются образы, пока в кластере Kubernetes существуют объекты, использующие их (например, все значения image в Deployment’ах). Другими словами, если вы запустили что-то в кластере Kubernetes, то используемые образы ни при каких условиях не будут удалены. Подробнее об очистке можно прочитать здесь.

Чтобы автоматизировать очистку, добавим новую стадию cleanup в gitlab-ci.yml:

Cleanup:
  stage: cleanup
  script:
    - type multiwerf && source <(multiwerf use 1.1 stable)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO}
    - werf cleanup --stages-storage :local
  only:
    - schedules
Cleanup: stage: cleanup script: - type multiwerf && source <(multiwerf use 1.1 stable) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO} - werf cleanup --stages-storage :local only: - schedules

После этого добавим новую задачу в планировщик, чтобы GitLab автоматически запускал cleanup (раздел CI/CD → Schedules):

В настройках указываем необходимое нам время запуска и ветку. Например, 4 утра:

После этого каждый день в 4 утра будет запускаться автоматическая очистка образов.