Настройка CI/CD с 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 **/*.jsci.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 **/*.jsct.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-cifrom-github-ctfrom-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.jspackage.jsonpackage-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==" }
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы: