GitHub Actions для построения CD в Yandex Cloud
Надеюсь вы уже знакомы с тем, что такое GitHub Actions и для чего они вам могут быть полезны. Если нет, то могу посоветовать хороший доклад и его текстовую расшифровку на эту тему.
Тут же я расскажу про экшены, которые помогут вам интегрироваться с Yandex Cloud.
Если у вас есть идея, какого экшена не хватает, то заведите тему в этом репозитории, расскажите подробно, что он должен делать и возможно его реализуют.
В предыдущем посте я рассказал, как залогиниться в Docker в GitHub Action и запушить собранный image в Container Registry в Яндекс Облаке.
Теперь расскажу как из этого образа развернуть контейнер. В Yandex Cloud для этого есть как минимум 3 опции:
- Виртуальная машина, созданная из Container Optimized Image;
- Serverless Container;
- Managed K8s кластер.
Ниже я расскажу про первые два варианта.
Так же вам может захотеться деплоить новые версии serverless функций непосредственно из GitHub репозитория. Для этого тоже есть экшен.
Ну и напоследок рассмотрим еще два простых экшена: для получения секретов из Lockbox и сброса кэша в Yandex Cloud CDN.
Деплой в COI VM
Для этого нам понадобится в GitHub Workflow добавить следующий кусок.
- name: Deploy COI VM
id: deploy-coi
uses: yc-actions/yc-coi-deploy@v1
env:
IMAGE_URL: cr.yandex/crpk28lsfu91rns28316/yc-coi-github-action:${{ github.sha }}
SSH_KEY: ${{ secrets.SSH_KEY }}
with:
yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
folder-id: b1gbmkj63********
vm-name: yc-action-demo
vm-service-account-id: aje9nl4jk3********
vm-cores: 2
vm-memory: 2 GB
vm-core-fraction: 100
vm-zone-id: ru-central1-a
vm-subnet-id: e9bobc1ueq********
user-data-path: './user-data.yaml'
docker-compose-path: './docker-compose.yaml'
Разберем подробнее.
Для авторизации в API нам понадобится авторизованный ключ сервисного аккаунта. Как его создать подробно можно прочитать в документации IAM. Далее его нужно положить в секреты на GitHub.
Так же необходимо указать folder-id
каталога в котором будет развернута ВМ. В параметр vm-name
следует передать имя виртуальной машины, на которой разворачивать контейнер. Если такой машины нет, то она будет создана в ходе выполнения экшена. Т.к. я постарался упростить этап конфигурирования создаваемой ВМ, может так случиться, что вам не хватит каких-либо параметров. В таком случае вам нужно создать ВМ любым другим способом (UI, CLI, API, Terraform), а этому экшену останется лишь подкладывать новый docker-compose файл на ВМ через апдейт метадаты.
Вот мы и подошли к тому как будет разворачиваться контейнер на ВМ. Для этого в репозитории должен быть файл docker-compose.yaml
в котором нужно описать конфигурацию разворачиваемого одного или нескольких контейнеров. Для того чтобы на этом этапе передать в файл некоторые переменные можно пользоваться mustache-синтакисисом. Например:
version: '3.7'
services:
logs:
container_name: logs-app
image: {{ env.IMAGE_URL }}
restart: always
Также нам понадобится файл user-data.yaml
примерно такого содержания:
#cloud-config
users:
- name: username
groups: sudo
shell: /bin/bash
sudo: [ 'ALL=(ALL) NOPASSWD:ALL' ]
ssh-authorized-keys:
- {{ env.SSH_KEY }}
Здесь тоже можно использовать подстановку значений. Логиниться на созданную ВМ по ssh нужно будет от имени пользователя username
или того которого вы укажете в user-data
.
Полный код примера репозитория с этим workflow можно найти тут.
Деплой в Serverless Containers
Подход тут аналогичный, отличия лишь в используемом action.
- name: Deploy Serverless Container
id: deploy-sls-container
uses: yc-actions/yc-sls-container-deploy@v1
with:
yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
container-name: yc-action-demo
folder-id: bbajn5q2d74c********
revision-service-account-id: ajeqnasj95o7********
revision-cores: 1
revision-memory: 512Mb
revision-core-fraction: 100
revision-concurrency: 8
revision-image-url: cr.yandex/crp00000000000000000/my-cr-repo:${{ github.sha }}
revision-execution-timeout: 10
Так же как и в предыдущем примере мы указываем folder-id
, где искать, и на этот раз container-name
, который искать.
Затем будет получен id этого контейнера, с которым и будут производиться манипуляции с контейнером. Имя кажется более человекопонятным идентификатором, поэтому в инпутах экшенов используется именно оно.
Далее перечислены параметры с которыми будет развернута ревизия контейнера. Так же можно переда переменные окружения и другие параметры. Полный список можно найти в файле-описании action.yaml.
Деплой Serverless Function
Тут в отличие от предыдущих экшенов нам не нужно собирать docker image.
Если функция написана на языке для которого есть нативный рантайм, то можно просто при помощи этого экшена сразу создать новую версию функции.
Но тут я хотел бы разобрать чуть более сложный workflow, в котором мы сначала соберем js файлы из TypeScript исходников, а только потом создадим из них версию.
name: YC Function Deploy
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Install dependencies
run: npm ci
- run: npm run build --if-present
# Опционально можно запустить прогон тестов, если они есть
# - run: npm run test
- name: Deploy Function
id: sls-func
uses: yc-actions/yc-sls-function@v1.0.1
with:
yc-sa-json-credentials: ${{secrets.YC_SA_JSON_CREDENTIALS}}
folder-id: 'b1gbmkj6*******'
function-name: 'github-deploy'
runtime: 'nodejs16'
memory: '256Mb'
entrypoint: 'dist/index.handler'
environment: |
DEBUG=True
FOO=bar
include: |
./dist
package.json
exclude: |
**/*.ts
И так по шагам.
actions/checkout@v2
— Скачивает исходный код из репозитория.
actions/setup-node@v1
— Делает доступным в нашем окружении NodeJs. И как видно из переданных параметров, в этом случае мы используем 12 версию.
run: npm ci
— Ставит зависимости опираясь на package-lock.json
. Убедитесь, что он есть в вашем репозитории.
run: npm run build --if-present
— Билдим наши исходники на TypeScript в js.
И вот мы подошли к нашему экшену — yc-actions/yc-sls-function@v1.0.1
. Как видно на вход он принимает всё тот же folder-id
, а также имя функции, где мы будем создавать новую версию. Это обязательные параметры. Если такой функции нет в каталоге, то она будет создана.
Далее идут параметры версии функции. runtime
принимает значения описанные в документации.entrypoint
указывает на входную точку — функцию в коде, которая будет вызвана для обработки входящего сообщения. Оба эти параметра также обязательны.
Обратите внимание, что после environment
указана вертикальная черта |
— это способ передать многострочные значения в YAML. Именно в таком формате ожидаются:
— переменные окружения;
— списки путей, которые включить в архив при сборке iclude
;
— а также шаблоны путей, которые исключить из нее exclude
.
Получение секретов из Lockbox
Этот экшен прост относительно предыдущих и делает ровно то что указано в заголовке: получает секреты и складывает их в output, чтобы их можно было использовать в следующих шагах.
- name: Fetch secret
id: lockbox-secret
uses: yc-actions/yc-lockbox@v1
with:
yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
secret-id: e6q************
Обратиться к полученному секрету, лежащему по ключу foo
из другого шага можно так: ${{ steps.lockbox-secret.outputs.foo }}
.
Сброс кэша в YC CDN
Тоже довольно простой экшен. Он может пригодиться вам, когда вы собрали и разложили новую статику и хотите принудительно сбросить кэши в CDN.
- name: Purge CDN cache
id: purge-cache
uses: yc-actions/yc-cdn-cache@v1
with:
yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
cdn-resource-id: bc8********