В этой статье рассматриваются различные варианты настройки CI/CD с использованием GitHub CI/CD и werf.
Рабочий процесс в репозитории (набор GitHub workflow конфигураций) будет строиться на базе следующих заданий:
converge
— задание сборки, публикации образов и развёртывания приложения для одного из контуров кластера;dismiss
— задание удаления приложения (используется только для review окружений);cleanup
— задание очистки container registry.
Ключевыми шагами заданий будут наши комплексные GitHub Actions, werf/actions, которые сочетают в себе все необходимые шаги по подготовке окружения и выполнения требуемых werf команд. В статье будут рассмотрены примеры использования большинства из них, больше подробностей можно найти в репозитории набора.
Набор контуров в кластере Kubernetes может варьироваться в зависимости от многих факторов. В статье будут приведены различные варианты организации окружений для следующих:
- Production;
- Staging;
- Review.
Далее последовательно рассматриваются задания и различные варианты их организации. Изложение построено от общего к частному. В конце статьи приведён полный набор конфигураций для готовых workflow.
Независимо от workflow, все версии конфигураций подчиняются следующим правилам:
- Сборка и публикация является неотъемлемой частью развёртывания.
- Развёртывание/удаление review окружений:
- Развёртывание на review окружение возможен только в рамках Pull Request (PR).
- Review окружения удаляются автоматически при закрытии PR.
- Очистка запускается один раз в день по расписанию на master.
Для развёртываний review окружения, а также staging и production окружений предложены самые популярные варианты по организации. Каждый вариант для staging и production окружений сопровождается всевозможными способами отката релиза в production.
С общей информацией по организации CI/CD с помощью werf, а также информацией по конструированию своего workflow, можно ознакомиться в общей статье
Требования
- Кластер Kubernetes.
- Проект на GitHub.
- Приложение, которое успешно собирается и деплоится с помощью werf.
- Понимание основных концептов GitHub Actions.
Далее в примерах статьи будут использоваться виртуальные машины, предоставляемые GitHub, с OS Linux (
runs-on: ubuntu-latest
). Тем не менее, все примеры также справедливы для предустановленных self-hosted runners на базе любой OS
Сборка, публикация образов и развёртывание приложения
Прежде всего необходимо описать некий шаблон задания, общую часть для развёртывания в любой контур, что позволит сосредоточиться далее на правилах развёртывания и предложенных workflow.
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: ANY_ENV_NAME
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=ANY_ENV_URL"
Данное задание можно разбить на два независимых, но в нашем случае (сборка и публикации вызывается не на каждый коммит, а используется только совместно с развёртыванием) это избыточно и ухудшит читаемость конфигурации и время выполнения.
build-and-publish & deploy jobsbuild-and-publish: name: Build and Publish runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 0 - name: Build and Publish uses: werf/actions/build-and-publish@master with: kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }} deploy: name: Deploy needs: build-and-publish runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 0 - name: Deploy uses: werf/actions/deploy@v2 with: env: production kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Первый шаг, с которого начинается задание — Checkout code
, добавление исходных кодов приложения. При использовании сборщика werf (основная особенность которого — инкрементальная сборка) недостаточно, так называемого, shallow clone
с единственным коммитом, который создаёт action actions/checkout@v3
при использовании без параметров.
Базируясь на истории git, werf создаёт стадии. При отсутствии истории каждая сборка будет проходить без ранее собранных стадий, поэтому, крайне важно, использовать параметр fetch-depth: 0
для доступа ко всей истории для всех команд, которые используют стадии: при сборке, публикации и развёртывании (werf build
, werf converge
), запуске (werf run
) и т.д.
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
Следующим шагом используется action werf/actions/converge
, который объединяет все необходимые шаги, подготавливает окружение и вызывает соответствующую команду.
- name: Converge
uses: werf/actions/converge@v2
with:
env: ANY_ENV_NAME
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "env_url=ANY_ENV_URL"
Среди предустановленного ПО на виртуальных машинах GitHub уже установлен kubectl
, поэтому пользователю остаётся только:
- определиться с конфигурацией kubeconfig;
- создать секретную переменную
KUBE_CONFIG_BASE64_DATA
с контентом файла kubeconfig (cat ~/.kube/config | base64
) в Settings/Secrets проекта на GitHub. - прокинуть секретную переменную
secrets.KUBE_CONFIG_BASE64_DATA
в используемый werf action:
- name: Converge
uses: werf/actions/converge@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Конфигурация задания достаточно проста, поэтому хочется сделать акцент на том, чего в ней нет — явной авторизации в container registry, вызова werf cr login
.
В простейшем случае, при использовании встроенного container registry, авторизация выполняется автоматически при вызове команды werf ci-env
. В качестве необходимых аргументов используются переменные окружения GitHub, секретная переменная GITHUB_TOKEN
, а также имя пользователя (GITHUB_ACTOR
) инициировавшего запуск workflow.
Если необходимо выполнить авторизацию с произвольными учётными данными или с внешним container registry, то необходимо использовать готовый action для вашего container registry или просто выполнить werf cr login
перед.
Рассмотрим оставшиеся используемые параметры на этом шаге:
- name: Converge
uses: werf/actions/converge@v2
with:
env: ANY_ENV_NAME
env:
WERF_SET_ENV_URL: "env_url=ANY_ENV_URL"
Для каждого контура необходимо определить окружение. В нашем случае оно определяется следующими параметрами:
- именем (
ANY_ENV_NAME
) и; - URL (
ANY_ENV_URL
).
Для того, чтобы по-разному конфигурировать приложение для используемых контуров кластера в helm-шаблонах можно использовать Go-шаблоны и переменную .Values.werf.env
, что соответствует значению, которое задаётся в качестве параметра у action (env
).
Адрес окружения является необязательным. В данной статье используется исключительно в качестве примера организации окружений и для демонстрации работы с опциями werf при использовании actions (все опции werf можно задавать через переменные окружения)
Адрес окружения, URL для доступа к разворачиваемому в контуре приложению, который передаётся параметром env_url
, может использоваться в helm-шаблонах, например, для конфигурации Ingress-ресурсов. Для того, чтобы определить URL, используется переменная окружения WERF_SET_ENV_URL
, которая соответствует вызову werf с опцией --set
(WERF_SET_<ANY_NAME>
).
Если для шифрования значений переменных вы используете werf, то вам также необходимо добавить
encryption key
в переменнуюWERF_SECRET_KEY
в Settings/Secrets проекта и добавить секрет в секцию env
Далее будут представлены популярные стратегии и практики, на базе которых мы предлагаем выстраивать ваши процессы в GitHub Actions.
Варианты организации review окружения
Как уже было сказано ранее, review окружение — это динамический контур, поэтому помимо развёртывания у этого окружения также будет и очистка.
Рассмотрим базовые GitHub workflow файлы, которые лягут в основу всех предложенных вариантов.
Сначала разберём файл .github/workflows/review_deployment.yml
.
name: Review Deployment
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
В нём пропущено условие запуска, т.к. оно зависит от выбранного варианта организации.
От базовой конфигурации задание отличается только появившимся шагом Define environment url
.
На этом шаге генерируется уникальный URL для каждого PR, по которому после развёртывания будет доступно наше приложение (при соответствующей организации helm templates).
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=env_url=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
Далее файл .github/workflows/review_deployment_dismiss.yml
.
name: Review Deployment Dismiss
on:
pull_request:
types: [closed]
jobs:
dismiss:
name: Dismiss
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Данный GitHub workflow будет выполняться при закрытии PR.
on:
pull_request:
types: [closed]
На шаге Dismiss
выполняется удаление review-релиза: werf удаляет helm-релиз и namespace в Kubernetes со всем его содержимым (werf dismiss).
Далее разберём основные стратегии при организации развёртывания review окружения.
Мы не ограничиваем вас предложенными вариантами, даже напротив — рекомендуем комбинировать их и создавать конфигурацию workflow под нужды вашей команды
№1 Вручную
Данный вариант реализует подход описанный в разделе «Развёртывание» на review из pull request по кнопке»
При таком подходе пользователь разворачивает и удаляет окружение, проставляя соответствующий лейбл (review_start
или review_stop
) в PR.
Он самый простой и может быть удобен в случае, когда развёртывания происходят редко и review окружение не используется при разработке. По сути, для проверки перед принятием PR.
name: Review Deployment
on:
pull_request:
types: [labeled]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
converge:
name: Converge
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Review Deployment Dismiss
on:
pull_request:
types: [labeled, closed]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_stop'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
dismiss:
name: Dismiss
if: github.event.label.name == 'review_stop' || github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
В данном варианте оба GitHub workflow ожидают проставление лейбла в PR.
on:
pull_request:
types: [labeled]
Если событие связано с добавлением лейбла review_start
или review_stop
, то выполняются задания соответствующего workflow.
Иначе, при проставлении произвольного лейбла — workflow запускается, но ни одно задание не выполняется и он помечается как skipped
.
Используя фильтрацию по статусу, можно проследить активность в review окружении.
Шаг Label taking off
снимает лейбл, который инициирует запуск workflow. Он используется в качестве индикатора обработки пользовательского запроса на развёртывание и остановку review окружения (а бонусом, мы можем отслеживать историю изменений и развёртываний по логу в PR).
labels:
name: Label taking off
runs-on: ubuntu-latest
if: github.event.label.name == 'review_stop'
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
№2 Автоматически по имени ветки
Данный вариант реализует подход описанный в разделе Развёртывание на review из ветки по шаблону автоматически
В предложенном ниже варианте автоматический релиз выполняется для каждого коммита в PR, в случае, если имя git-ветки содержит review
.
name: Review Deployment
on:
pull_request:
types:
- opened
- reopened
- synchronize
jobs:
converge:
name: Converge
if: ${{ contains( github.head_ref, 'review' ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Review Deployment Dismiss
on:
pull_request:
types: [closed]
jobs:
dismiss:
name: Dismiss
if: ${{ contains( github.head_ref, 'review' ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Развёртывание инициируется при коммите в ветку, открытии и переоткрытии PR, что соответствует набору событий по умолчанию для pull_request
:
// equal conditions
on:
pull_request:
types:
- opened
- reopened
- synchronize
on:
pull_request:
№3 Полуавтоматический режим с лейблом (рекомендованный)
Данный вариант реализует подход описанный в разделе «Развёртывание на review из pull request автоматически после ручной активации»
Полуавтоматический режим с лейблом — это комплексное решение, объединяющие первые два варианта.
При проставлении специального лейбла, в примере ниже review
, пользователь активирует автоматическое развёртывание в review окружения для каждого коммита.
При снятии лейбла автоматически запускается удаление review-релиза.
name: Optional Review Deployment
on:
pull_request:
types:
- labeled
- unlabeled
- synchronize
jobs:
optional_converge_or_dismiss:
name: Optional Converge or Dismiss
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
if: contains( github.event.pull_request.labels.*.name, 'review' )
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
if: contains( github.event.pull_request.labels.*.name, 'review' )
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
if: "!contains( github.event.pull_request.labels.*.name, 'review' )"
name: Review Deployment Dismiss
on:
pull_request:
types: [closed]
jobs:
dismiss:
name: Dismiss
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Развёртывание инициируется при коммите в ветку, добавлении и снятии лейбла в PR, что соответствует следующему набору событий для pull_request
:
pull_request:
types:
- labeled
- unlabeled
- synchronize
Варианты организации staging и production окружений
Предложенные далее варианты являются наиболее эффективными комбинациями правил развёртывания staging и production окружений.
В нашем случае, данные окружения являются определяющими, поэтому названия вариантов соответствуют названиям окончательных workflow, предложенных в конце статьи.
№1 Fast and Furious (рекомендованный)
Данный вариант реализует подходы описанные в разделах «Развёртывание на production из master автоматически» и «Развёртывание на production-like из pull request по кнопке»
Развёртывание в production происходит автоматически при любых изменениях в master. Выполнить развёртывание в staging можно только проставив соответствующий лейбл в PR.
name: Staging Deployment
on:
pull_request:
types: [labeled]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'staging_deploy'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
converge:
name: Converge
if: github.event.label.name == 'staging_deploy'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
branches: [master]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
Варианты отката изменений в production:
- revert изменений в master (рекомендованный);
- развёртывание стабильного PR.
№2 Push the Button (*)
Данный вариант реализует подходы описанные в разделах «Развёртывание на production из master по кнопке» и «Развёртывание на staging из master автоматически»
Мы не рекомендуем использовать данный подход с GitHub, так как в настоящий момент система не имеет достаточного инструментария для комфортной работы с GitHub Workflow. Работа с конкретными коммитами и ручной запуск отчасти сводятся к использованию внешних событий, repository_dispatch, но большинство кейсов остаются без решений, что снижает ценность и зрелость данного подхода.
Развёртывание production осуществляется вручную на master, а развёртывание в staging происходит автоматически при любых изменениях в master.
name: Staging Deployment
on:
push:
branches: [master]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
repository_dispatch:
types: [production_deployment]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
Имеем следующее условие для релиза в production:
on:
repository_dispatch:
types: [production_deployment]
Чтобы запустить данный workflow, достаточно выполнить следующий запрос:
curl \
--location --request POST 'https://api.github.com/repos/<company>/<project>/dispatches' \
--header 'Content-Type: application/json' \
--header 'Accept: application/vnd.github.everest-preview+json' \
--header "Authorization: token $GITHUB_TOKEN" \
--data-raw '{
"event_type": "production_deployment",
"client_payload": {}
}'
Для использования данного подхода можно добавить скрипт в репозиторий проекта, использовать postman, плагин для браузера и т.д.
Варианты отката изменений в production:
- развёртывание стабильного PR и инициализация развёртывания при помощи repository_dispatch.
№3 Tag everything (*)
Данный вариант реализует подходы описанные в разделах «Развёртывание на production из тега автоматически» и «Развёртывание на staging из master по кнопке»
Мы не рекомендуем использовать данный подход с GitHub, так как в настоящий момент система не имеет достаточного инструментария для комфортной работы с GitHub Workflow. Работа с конкретными коммитами и ручной запуск отчасти сводятся к использованию внешних событий, repository_dispatch, но большинство кейсов остаются без решений, что снижает ценность и зрелость данного подхода.
Развёртывание в production выполняется при проставлении тега, а в staging осуществляется вручную на master.
name: Staging Deployment
on:
repository_dispatch:
types: [staging_deployment]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
tags:
- v*
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
on:
repository_dispatch:
types: [staging_deployment]
Чтобы запустить данный workflow, достаточно выполнить следующий запрос:
curl \
--location --request POST 'https://api.github.com/repos/<company>/<project>/dispatches' \
--header 'Content-Type: application/json' \
--header 'Accept: application/vnd.github.everest-preview+json' \
--header "Authorization: token $GITHUB_TOKEN" \
--data-raw '{
"event_type": "staging_deployment",
"client_payload": {}
}'
Для использования данного подхода можно добавить скрипт в репозиторий проекта, использовать postman, плагин для браузера и т.д.
Варианты отката изменений в production:
- создание нового тега на старый коммит.
№4 Branch, branch, branch!
Данный вариант реализует подходы описанные в разделах «Развёртывание на production из ветки автоматически» и «Развёртывание на production-like из ветки автоматически»
Развёртывание в production происходит автоматически при любых изменениях в ветке production, а в staging при любых изменениях в ветке master.
name: Staging Deployment
on:
push:
branches:
- master
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
branches:
- production
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
Варианты отката изменений в production:
- revert изменений в ветке production;
- revert изменений в master и fast-forward merge в ветку production;
- удаление коммита из ветки production и push-force.
Очистка образов
name: Cleanup container registry
on:
schedule:
- cron: '0 6 * * *'
repository_dispatch:
types: [cleanup]
jobs:
cleanup:
name: Cleanup
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
- name: Cleanup
uses: werf/actions/cleanup@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Первый шаг, с которого начинается задание — Checkout code
, добавление исходных кодов приложения.
Большинство политик очистки в werf базируется на примитивах git (на коммите, ветке и теге), поэтому использование action actions/checkout@v3
без дополнительных параметров и действий может приводить к неожиданному удалению образов. Мы рекомендуем использовать следующие шаги для корректной работы.
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
В werf встроен эффективный механизм очистки, который позволяет избежать переполнения container registry и диска сборочного узла от устаревших и неиспользуемых образов. Более подробно ознакомиться с возможностями очистки, встроенными в werf, можно здесь.
Полный набор конфигураций для готовых workflow
Детали workflow
Подробнее про workflow можно почитать в отдельной статье
- Развёртывание на review контур по стратегии №3 Полуавтоматический режим с лейблом (рекомендованный).
- Развёртывание на staging и production контуры осуществляется по стратегии №1 Fast and Furious (рекомендованный).
- Очистка стадий выполняется по расписанию раз в сутки.
Конфигурации
name: Optional Review Deployment
on:
pull_request:
types:
- labeled
- unlabeled
- synchronize
jobs:
optional_converge_or_dismiss:
name: Optional Converge or Dismiss
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
if: contains( github.event.pull_request.labels.*.name, 'review' )
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
if: contains( github.event.pull_request.labels.*.name, 'review' )
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
if: "!contains( github.event.pull_request.labels.*.name, 'review' )"
name: Review Deployment Dismiss
on:
pull_request:
types: [closed]
jobs:
dismiss:
name: Dismiss
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Staging Deployment
on:
pull_request:
types: [labeled]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'staging_deploy'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
converge:
name: Converge
if: github.event.label.name == 'staging_deploy'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
branches: [master]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
name: Cleanup container registry
on:
schedule:
- cron: '0 6 * * *'
repository_dispatch:
types: [cleanup]
jobs:
cleanup:
name: Cleanup
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
- name: Cleanup
uses: werf/actions/cleanup@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Детали workflow
Подробнее про workflow можно почитать в отдельной статье
Мы не рекомендуем использовать данный подход с GitHub, так как в настоящий момент система не имеет достаточного инструментария для комфортной работы с GitHub Workflow. Работа с конкретными коммитами и ручной запуск отчасти сводятся к использованию внешних событий, repository_dispatch, но большинство кейсов остаются без решений, что снижает ценность и зрелость данного подхода.
- Развёртывание на review контур по стратегии №1 Вручную.
- Развёртывание на staging и production контуры осуществляется по стратегии №2 Push the Button.
- Очистка стадий выполняется по расписанию раз в сутки.
Конфигурации
name: Review Deployment
on:
pull_request:
types: [labeled]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
converge:
name: Converge
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Review Deployment Dismiss
on:
pull_request:
types: [labeled, closed]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_stop'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
dismiss:
name: Dismiss
if: github.event.label.name == 'review_stop' || github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Staging Deployment
on:
push:
branches: [master]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
repository_dispatch:
types: [production_deployment]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
name: Cleanup container registry
on:
schedule:
- cron: '0 6 * * *'
repository_dispatch:
types: [cleanup]
jobs:
cleanup:
name: Cleanup
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
- name: Cleanup
uses: werf/actions/cleanup@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Детали workflow
Подробнее про workflow можно почитать в отдельной статье
Мы не рекомендуем использовать данный подход с GitHub, так как в настоящий момент система не имеет достаточного инструментария для комфортной работы с GitHub Workflow. Работа с конкретными коммитами и ручной запуск отчасти сводятся к использованию внешних событий, repository_dispatch, но большинство кейсов остаются без решений, что снижает ценность и зрелость данного подхода.
- Развёртывание на review контур по стратегии №1 Вручную.
- Развёртывание на staging и production контуры осуществляется по стратегии №3 Tag everything.
- Очистка стадий выполняется по расписанию раз в сутки.
Конфигурации
name: Review Deployment
on:
pull_request:
types: [labeled]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
converge:
name: Converge
if: github.event.label.name == 'review_start'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Review Deployment Dismiss
on:
pull_request:
types: [labeled, closed]
jobs:
labels:
name: Label taking off
if: github.event.label.name == 'review_stop'
runs-on: ubuntu-latest
steps:
- name: Take off label
uses: actions/github-script@v1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: >
github.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: '${{ github.event.label.name }}'
})
dismiss:
name: Dismiss
if: github.event.label.name == 'review_stop' || github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Staging Deployment
on:
repository_dispatch:
types: [staging_deployment]
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
tags:
- v*
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
name: Cleanup container registry
on:
schedule:
- cron: '0 6 * * *'
repository_dispatch:
types: [cleanup]
jobs:
cleanup:
name: Cleanup
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
- name: Cleanup
uses: werf/actions/cleanup@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
Детали workflow
Подробнее про workflow можно почитать в отдельной статье
- Развёртывание на review контур по стратегии №2 Автоматически по имени ветки.
- Развёртывание на staging и production контуры осуществляется по стратегии №4 Branch, branch, branch!.
- Очистка стадий выполняется по расписанию раз в сутки.
Конфигурации
name: Review Deployment
on:
pull_request:
types:
- opened
- reopened
- synchronize
jobs:
converge:
name: Converge
if: ${{ contains( github.head_ref, 'review' ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Define environment url
run: |
pr_id=${{ github.event.number }}
github_repository_id=$(echo ${GITHUB_REPOSITORY} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)
echo WERF_SET_ENV_URL=envUrl=http://${github_repository_id}-${pr_id}.kube.DOMAIN >> $GITHUB_ENV
- name: Converge
uses: werf/actions/converge@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Review Deployment Dismiss
on:
pull_request:
types: [closed]
jobs:
dismiss:
name: Dismiss
if: ${{ contains( github.head_ref, 'review' ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Dismiss
uses: werf/actions/dismiss@v2
with:
env: review-${{ github.event.number }}
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
name: Staging Deployment
on:
push:
branches:
- master
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: staging
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=http://staging-company.kube.DOMAIN"
name: Production Deployment
on:
push:
branches:
- production
jobs:
converge:
name: Converge
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Converge
uses: werf/actions/converge@v2
with:
env: production
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}
env:
WERF_SET_ENV_URL: "envUrl=https://www.company.org"
name: Cleanup container registry
on:
schedule:
- cron: '0 6 * * *'
repository_dispatch:
types: [cleanup]
jobs:
cleanup:
name: Cleanup
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Fetch all history for all tags and branches
run: git fetch --prune --unshallow
- name: Cleanup
uses: werf/actions/cleanup@v2
with:
kube-config-base64-data: ${{ secrets.KUBE_CONFIG_BASE64_DATA }}