Настройка CI/CD между Yandex Cloud Functions и GitHub
GitHub
В этом руководстве вы настроите CI/CD между Cloud Functions и GitHub с помощью федерации сервисных аккаунтов Yandex Identity and Access Management и развернете функции Cloud Functions через запуск рабочих процессов
Чтобы настроить CI/CD:
- Подготовьте облако к работе.
- Создайте репозиторий.
- Подготовьте инфраструктуру в Yandex Cloud.
- Настройте репозиторий.
- Проверьте рабочие процессы.
Если созданные ресурсы вам больше не нужны, удалите их.
Подготовьте облако к работе
Зарегистрируйтесь в Yandex Cloud и создайте платежный аккаунт:
- Перейдите в консоль управления
, затем войдите в Yandex Cloud или зарегистрируйтесь. - На странице Yandex Cloud Billing
убедитесь, что у вас подключен платежный аккаунт, и он находится в статусеACTIVE
илиTRIAL_ACTIVE
. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Необходимые платные ресурсы
В стоимость поддержки инфраструктуры для этого практического руководства входят:
- Плата за количество вызовов функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик (см. тарифы Cloud Functions).
- Плата за запись и хранение логов функции в лог-группе (см. тарифы Yandex Cloud Logging).
Создайте репозиторий
Создайте
Имена репозитория и пользователя GitHub потребуются в дальнейшем.
Подготовьте инфраструктуру в Yandex Cloud
Создайте сервисный аккаунт
От имени сервисного аккаунта с ролью functions.admin
GitHub будет создавать функцию и ее версии.
- В консоли управления
выберите каталог, в котором вы будете создавать инфраструктуру. - В списке сервисов выберите Identity and Access Management.
- Нажмите Создать сервисный аккаунт.
- Введите имя сервисного аккаунта:
ci-cd-github-sa
. - Нажмите
Добавить роль и выберите рольfunctions.admin
. - Нажмите Создать.
Если у вас еще нет интерфейса командной строки Yandex Cloud (CLI), установите и инициализируйте его.
По умолчанию используется каталог, указанный при создании профиля CLI. Чтобы изменить каталог по умолчанию, используйте команду yc config set folder-id <идентификатор_каталога>
. Также для любой команды вы можете указать другой каталог с помощью параметров --folder-name
или --folder-id
.
-
Создайте сервисный аккаунт:
yc iam service-account create --name ci-cd-github-sa
Результат:
id: ajehqs5gee2e******** folder_id: b1g681qpemb4******** created_at: "2025-07-12T17:53:28.180991864Z" name: ci-cd-github-sa
-
Назначьте роль
functions.admin
сервисному аккаунту:yc resource-manager folder add-access-binding <имя_или_идентификатор_каталога> \ --role functions.admin \ --subject serviceAccount:<идентификатор_сервисного_аккаунта>
Результат:
effective_deltas: - action: ADD access_binding: role_id: functions.admin subject: id: ajejocsfa1jj******** type: serviceAccount
Чтобы создать сервисный аккаунт, воспользуйтесь методом REST API create для ресурса ServiceAccount или вызовом gRPC API ServiceAccountService/Create.
Чтобы назначить сервисному аккаунту роль functions.admin
на каталог, воспользуйтесь методом REST API updateAccessBindings для ресурса Folder или вызовом gRPC API FolderService/UpdateAccessBindings.
Создайте федерацию сервисных аккаунтов
Федерация сервисных аккаунтов необходима для настройки обмена токенов GitHub на IAM-токены Yandex Cloud.
- В консоли управления
выберите сервис Identity and Access Management. - На панели слева выберите
Федерации сервисных аккаунтов. - Нажмите Создать федерацию.
- В поле Значение Issuer (iss) введите URL OIDC-провайдера:
https://token.actions.githubusercontent.com
. - В поле Допустимые значения Audience (aud) введите получателя токена:
https://github.com/<имя_пользователя_GitHub>
. - В поле Адрес JWKS введите URL списка публичных ключей:
https://token.actions.githubusercontent.com/.well-known/jwks
. - В поле Имя введите имя федерации:
ci-cd-github-federation
. - Нажмите Создать.
Выполните команду:
yc iam workload-identity oidc federation create \
--name ci-cd-github-federation \
--issuer "https://token.actions.githubusercontent.com" \
--audiences "https://github.com/<имя_пользователя_GitHub>" \
--jwks-url "https://token.actions.githubusercontent.com/.well-known/jwks"
Где:
--name
— имя создаваемой федерации.--issuer
— URL OIDC-провайдера.--audiences
— ресурсы, для которых будет предназначен получаемый токен. Вы можете через запятую задать одновременно несколько ресурсов-получателей IAM-токена.--jwks-url
— URL, по которому можно получить актуальный открытый ключ, выпущенный OIDC-провайдером и используемый для проверки подписи JWT .
Результат:
id: ajeoerss1fa4********
name: ci-cd-github-federation
folder_id: b1g681qpemb4********
enabled: true
audiences:
- https://github.com/eip********
issuer: https://token.actions.githubusercontent.com
jwks_url: https://token.actions.githubusercontent.com/.well-known/jwks
created_at: "2025-07-24T18:20:33.546066838Z"
Чтобы создать федерацию сервисных аккаунтов, воспользуйтесь методом REST API create для ресурса Federation или вызовом gRPC API FederationService/Create.
В запросе укажите значения параметров:
issuer
—https://token.actions.githubusercontent.com
.audiences
—https://github.com/<имя_пользователя_GitHub>
.jwks-url
/jwks_url
—https://token.actions.githubusercontent.com/.well-known/jwks
.
Создайте привязки сервисного аккаунта к федерации
С помощью привязок вы настроите связь между федерацией сервисных аккаунтов, сервисным аккаунтом и GitHub.
-
В консоли управления
выберите сервис Identity and Access Management. -
Выберите сервисный аккаунт
ci-cd-github-sa
. -
Перейдите на вкладку
Федерации сервисных аккаунтов. -
Нажмите Привязать к федерации.
-
В поле Федерация сервисных аккаунтов выберите федерацию
ci-cd-github-federation
. -
В поле Значение Subject (sub) укажите идентификатор внешнего субъекта для тестового окружения:
repo:<имя_пользователя_GitHub>/<имя_репозитория>:environment:preprod
.Окружение
preprod
будет использоваться далее в файлахci.yml
иct.yml
. -
Нажмите Привязать.
Аналогичным способом создайте привязку с идентификатором внешнего субъекта для продакшен-окружения: repo:<имя_пользователя_GitHub>/<имя_репозитория>:ref:refs/heads/main
.
Выполните команды, чтобы создать привязки для тестового и продакшен-окружения:
yc iam workload-identity federated-credential create \
--service-account-id <идентификатор_сервисного_аккаунта> \
--federation-id <идентификатор_федерации> \
--external-subject-id "repo:<имя_пользователя_GitHub>/<имя_репозитория>:environment:preprod"
yc iam workload-identity federated-credential create \
--service-account-id <идентификатор_сервисного_аккаунта> \
--federation-id <идентификатор_федерации> \
--external-subject-id "repo:<имя_пользователя_GitHub>/<имя_репозитория>:ref:refs/heads/main"
Где:
-
--service-account-id
— идентификатор сервисного аккаунтаci-cd-github-sa
. -
--federation-id
— идентификатор федерации сервисных аккаунтовci-cd-github-federation
. -
--external-subject-id
— идентификатор внешнего субъекта.Окружение
preprod
будет использоваться далее в файлахci.yml
иct.yml
.
Результат:
id: ajek9t6ojc53********
service_account_id: ajejocsfa1jj********
federation_id: ajeoerss1fa4********
external_subject_id: repo:eip********/ci-cd-github-repo:environment:preprod
created_at: "2025-07-24T18:21:01.103940710Z"
id: aje82obioirm********
service_account_id: ajejocsfa1jj********
federation_id: ajeoerss1fa4********
external_subject_id: repo:eip********/ci-cd-github-repo:ref:refs/heads/main
created_at: "2025-07-24T18:21:13.925210300Z"
Чтобы создать привязку, воспользуйтесь методом REST API create для ресурса FederatedCredential или вызовом gRPC API FederatedCredentialService/Create.
В запросе укажите значение параметра externalSubjectId
/external_subject_id
:
-
Для тестового окружения —
repo:<имя_пользователя_GitHub>/<имя_репозитория>:environment:preprod
.Окружение
preprod
будет использоваться далее в файлахci.yml
иct.yml
. -
Для продакшен-окружения —
repo:<имя_пользователя_GitHub>/<имя_репозитория>:ref:refs/heads/main
.
Настройте репозиторий
Подготовьте файлы проекта
Склонируйте репозиторий:
git clone https://github.com/yandex-cloud-examples/yc-serverless-ci-cd-github
В репозитории вы увидите:
- папку
.github/workflows
с файлами рабочих процессов:cd.yml
,ci.yml
иct.yml
; - код функции
index.js
и описание зависимостейpackage.json
,package-lock.json
.
-
Создайте папку
yc-serverless-ci-cd-github
и перейдите в нее. -
Создайте файл
index.js
и вставьте в него код:const sharp = require('sharp'); async function cropImage(imageBase64, width, height) { try { // Decode image from base64 const buffer = Buffer.from(imageBase64, 'base64'); const croppedBuffer = await sharp(buffer) .resize(width, height) .toBuffer(); const croppedImageBase64 = croppedBuffer.toString('base64'); return croppedImageBase64; } catch (error) { console.error('Error cropping image:', error); throw error; } } module.exports.handler = async function (event, context) { return { content: await cropImage(event.queryStringParameters.content, event.queryStringParameters.width, event.queryStringParameters.height) }; };
-
Создайте файл
package.json
и вставьте в него код:{ "name": "from-github", "version": "1.0.0" }
-
Выполните команду:
npm install --package-lock-only
В результате выполнения команды появится файл
package-lock.json
. -
Создайте файлы
cd.yml
,ci.yml
,ct.yml
и вставьте в них код с нужными параметрами:cd.yml
permissions: id-token: write # Это необходимо для запроса JWT on: push: branches: - main paths-ignore: - '.github/**' # Это позволит игнорировать изменения в файлах рабочих процессов release: types: - published # Позволяет запускать этот рабочий процесс вручную из вкладки Actions workflow_dispatch: env: FOLDER_ID: <идентификатор_каталога> SA_ID: <идентификатор_сервисного_аккаунта> FUNCTION_NAME: from-github-cd FUNCTION_RUNTIME: nodejs22 FUNCTION_ENTRYPOINT: index.handler FUNCTION_MEMORY: "128mb" FUNCTION_SOURCEROOT: . jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy Function id: sls-func uses: yc-actions/yc-sls-function@v3.1.0 with: yc-sa-id: ${{env.SA_ID}} folder-id: ${{env.FOLDER_ID}} function-name: ${{env.FUNCTION_NAME}} runtime: ${{env.FUNCTION_RUNTIME}} entrypoint: ${{env.FUNCTION_ENTRYPOINT}} memory: ${{env.FUNCTION_MEMORY}} source-root: ${{env.FUNCTION_SOURCEROOT}} include: | **/*.json **/*.js
ci.yml
permissions: id-token: write # Это необходимо для запроса JWT on: push: branches: [ feature** ] paths-ignore: - '.github/**' # Позволяет запускать этот рабочий процесс вручную из вкладки Actions workflow_dispatch: env: FOLDER_ID: <идентификатор_каталога> SA_ID: <идентификатор_сервисного_аккаунта> FUNCTION_NAME: from-github-ci FUNCTION_RUNTIME: nodejs22 FUNCTION_ENTRYPOINT: index.handler FUNCTION_MEMORY: "128mb" FUNCTION_SOURCEROOT: . jobs: build: environment: preprod runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy Function id: sls-func uses: yc-actions/yc-sls-function@v3.1.0 with: yc-sa-id: ${{env.SA_ID}} folder-id: ${{env.FOLDER_ID}} function-name: ${{env.FUNCTION_NAME}} runtime: ${{env.FUNCTION_RUNTIME}} entrypoint: ${{env.FUNCTION_ENTRYPOINT}} memory: ${{env.FUNCTION_MEMORY}} source-root: ${{env.FUNCTION_SOURCEROOT}} include: | **/*.json **/*.js
ct.yml
permissions: id-token: write # Это необходимо для запроса JWT on: pull_request: branches: [ main ] paths-ignore: - '.github/**' # Позволяет запускать этот рабочий процесс вручную из вкладки Actions workflow_dispatch: env: FOLDER_ID: <идентификатор_каталога> SA_ID: <идентификатор_сервисного_аккаунта> FUNCTION_NAME: from-github-ct FUNCTION_RUNTIME: nodejs22 FUNCTION_ENTRYPOINT: index.handler FUNCTION_MEMORY: "128mb" FUNCTION_SOURCEROOT: . jobs: build: environment: preprod runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy Function id: sls-func uses: yc-actions/yc-sls-function@v3.1.0 with: yc-sa-id: ${{env.SA_ID}} folder-id: ${{env.FOLDER_ID}} function-name: ${{env.FUNCTION_NAME}} runtime: ${{env.FUNCTION_RUNTIME}} entrypoint: ${{env.FUNCTION_ENTRYPOINT}} memory: ${{env.FUNCTION_MEMORY}} source-root: ${{env.FUNCTION_SOURCEROOT}} include: | **/*.json **/*.js
Где:
-
FOLDER_ID
— идентификатор каталога, в котором вы выполняете руководство. -
SA_ID
— идентификатор сервисного аккаунта, привязанного к федерации. -
FUNCTION_NAME
— имя функции. В примерах используются имена:from-github-ci
from-github-ct
from-github-cd
-
FUNCTION_RUNTIME
— среда выполнения функции. -
FUNCTION_ENTRYPOINT
— точка входа функции. -
FUNCTION_MEMORY
— объем RAM функции. -
FUNCTION_SOURCEROOT
— путь к файлам функции в репозитории.
-
Добавьте файлы рабочих процессов в репозиторий
-
Склонируйте ваш репозиторий, если это еще не сделано:
git clone <URL_репозитория>
-
Скопируйте полученные файлы рабочих процессов в локальную копию вашего репозитория:
.github/workflows/cd.yml
.github/workflows/ci.yml
.github/workflows/ct.yml
-
Отправьте изменения в удаленный репозиторий:
git add . && git commit -m "Added workflows" && git push
Проверьте рабочие процессы
Последовательно запустите рабочие процессы CI, CT, CD и проверьте результаты их выполнения.
Запустите рабочий процесс CI
-
Переключитесь на ветку
main
:git checkout main
-
Получите изменения из удаленного репозитория:
git pull
-
Создайте новую ветку
feature/smoke-test
:git checkout -b feature/smoke-test
-
Скопируйте файлы функции в корневую папку локальной копии вашего репозитория:
index.js
package.json
package-lock.json
-
Сохраните изменения, создайте коммит и отправьте изменения в удаленный репозиторий:
git add . git commit -m "Added function" git push --set-upstream origin feature/smoke-test
После отправки изменений автоматически запустится рабочий процесс
.github/workflows/ci.yml
.Дождитесь завершения рабочего процесса. Статус и логи выполнения можно проверить на вкладке
Actions вашего репозитория.
Проверьте результат CI
- В консоли управления
выберите сервис Cloud Functions. - Выберите функцию
from-github-ci
. - Перейдите на вкладку
Тестирование. -
В поле Входные данные введите следующий код и нажмите
Запустить тест:{ "queryStringParameters": { "content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNgYAAAAAMAASsJTYQAAAAASUVORK5CYII=", "width": 100, "height": 100 } }
В разделе Результат тестирования появится ответ функции:
{ "content": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAANElEQVR4nO3BAQ0AAADCoPdPbQ43oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAujF1lAABe5jSrAAAAABJRU5ErkJggg==" }
Запустите рабочий процесс CT
Создайте пул-реквестfeature/smoke-test
в ветку main
через интерфейс GitHub.
После создания пул-реквеста автоматически запустится рабочий процесс .github/workflows/ct.yml
.
Дождитесь завершения рабочего процесса. Статус и логи выполнения можно проверить на вкладке
Проверьте результат CT
- В консоли управления
выберите сервис Cloud Functions. - Выберите функцию
from-github-ct
. - Перейдите на вкладку
Тестирование. -
В поле Входные данные введите следующий код и нажмите
Запустить тест:{ "queryStringParameters": { "content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNgYAAAAAMAASsJTYQAAAAASUVORK5CYII=", "width": 100, "height": 100 } }
В разделе Результат тестирования появится ответ функции:
{ "content": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAANElEQVR4nO3BAQ0AAADCoPdPbQ43oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAujF1lAABe5jSrAAAAABJRU5ErkJggg==" }
Запустите рабочий процесс CD
Смержите ваш пул-реквестmain
через интерфейс GitHub.
После этого автоматически запустится рабочий процесс .github/workflows/cd.yml
.
Дождитесь завершения рабочего процесса. Статус и логи выполнения можно проверить на вкладке
Проверьте результат CD
- В консоли управления
выберите сервис Cloud Functions. - Выберите функцию
from-github-cd
. - Перейдите на вкладку
Тестирование. -
В поле Входные данные введите следующий код и нажмите
Запустить тест:{ "queryStringParameters": { "content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNgYAAAAAMAASsJTYQAAAAASUVORK5CYII=", "width": 100, "height": 100 } }
В разделе Результат тестирования появится ответ функции:
{ "content": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAANElEQVR4nO3BAQ0AAADCoPdPbQ43oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAujF1lAABe5jSrAAAAABJRU5ErkJggg==" }
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы: