Настройка CI/CD для AWS Lambda с CodePipeline и SAM CLI

от автора

Приветствую! Сегодня я расскажу вам, как настроить CI/CD для AWS Lambda с использованием AWS CodePipeline и AWS SAM CLI. Если вы хотите автоматизировать процесс деплоя серверлесс-приложений и избавиться от рутины, то эта статья для вас.

Что нам понадобится

Перед началом работы убедитесь, что у вас есть:

  • AWS Account: доступ к облачным сервисам AWS.

  • AWS CLI: инструмент командной строки для взаимодействия с AWS.

  • AWS SAM CLI: утилита для разработки и деплоя серверлесс-приложений.

  • AWS CodePipeline: сервис для создания CI/CD пайплайнов.

  • AWS CodeBuild: для сборки и тестирования вашего кода.

  • GitHub или AWS CodeCommit: репозиторий для хранения исходного кода.

  • S3 Bucket: хранилище для артефактов сборки.

Настройка окружения

После всех установок необходимо настроить AWS CLI, чтобы он мог взаимодействовать с вашим аккаунтом AWS:

aws configure

Вам будет предложено ввести:

  • AWS Access Key ID и AWS Secret Access Key: их можно получить в AWS Console в разделе IAMUsers[Ваш пользователь]Security credentials.

  • Default region name: указываем регион, в котором будут развёрнуты ресурсы (например, us-east-1).

  • Default output format: обычно ставят json.

Создание серверлесс-приложения

Теперь создадим простое серверлесс-приложение, которое будем деплоить.

Запустим команду инициализации:

sam init --runtime python3.8 --name my-lambda-app --app-template hello-world
  • --runtime python3.8: выбираем язык и версию.

  • --name my-lambda-app: имя нашего проекта.

  • --app-template hello-world: используем шаблон «Hello World».

В результате появится структура проекта с базовой Lambda-функцией.

Дерево проекта будет выглядеть так:

my-lambda-app/ ├── README.md ├── events/ │   └── event.json ├── hello_world/ │   ├── app.py │   └── requirements.txt ├── template.yaml └── tests/     └── unit/         └── test_handler.py
  • app.py: содержит код Lambda-функции.

  • template.yaml: описывает инфраструктуру и конфигурацию для AWS.

  • tests/: содержит тесты для нашей функции.

Файл template.yaml является шаблоном CloudFormation и определяет ресурсы, которые будут созданы в AWS. Папка tests/ содержит тесты.

В файле hello_world/app.py находится простой обработчик:

import json  def lambda_handler(event, context):     message = "Hello, World!"     return {         'statusCode': 200,         'body': json.dumps({'message': message})     }

Эта функция возвращает простой JSON с сообщением.

Локальное тестирование функции

Прежде чем деплоить функцию, убедимся, что она работает локально.

Переходим в корневой каталог проекта и установим необходимые зависимости:

pip install -r hello_world/requirements.txt

Если requirements.txt пуст, значит дополнительных пакетов не требуется.

SAM CLI позволяет запускать функцию локально, имитируя API Gateway:

sam local start-api

Вы увидите сообщение, что сервер запущен на http://127.0.0.1:3000/hello.

Открываем новый терминал и выполняем запрос:

curl http://127.0.0.1:3000/hello

Вы должны получить ответ:

{"message": "Hello, World!"}

Это означает, что функция работает корректно и готова к деплою.

Подготовка к деплою

Перед тем как настроить CI/CD, нужно подготовить инфраструктуру для деплоя.

AWS SAM использует S3 для хранения артефактов сборки. Создадим бакет:

aws s3 mb s3://my-lambda-artifacts-bucket

Важно заменить my-lambda-artifacts-bucket на уникальное имя бакета.

S3 бакет необходим для хранения упакованного кода функции, который затем используется при деплое с помощью CloudFormation.

Соберём приложение и подготовим его к деплою:

sam package \     --output-template-file packaged.yaml \     --s3-bucket my-lambda-artifacts-bucket
  • sam package: упаковывает ваш код и загружает его в S3, обновляя ссылки в шаблоне.

  • --output-template-file: файл, в который будет записан обновлённый шаблон CloudFormation.

  • --s3-bucket: бакет, куда будут загружены артефакты.

Эта команда подготавливает всё необходимое для деплоя и генерирует обновлённый шаблон, который указывает на артефакты в S3.

Можно проверить деплой вручную, чтобы убедиться, что всё работает:

sam deploy \     --template-file packaged.yaml \     --stack-name my-lambda-stack \     --capabilities CAPABILITY_IAM 
  • sam deploy: выполняет деплой вашего приложения в AWS.

  • --stack-name: имя стека CloudFormation, который будет создан или обновлён.

  • --capabilities: подтверждаем создание IAM ролей, необходимых для работы функции.

После успешного деплоя вы получите URL для вызова функции. Попробуйте вызвать её и убедитесь, что она работает как ожидается.

Настройка репозитория

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

В корне проекта инициализируем репозиторий:

git init git add . git commit -m "Initial commit"

Это позволяет отслеживать изменения в коде и интегрировать систему контроля версий с CI/CD пайплайном.

Создадим новый репозиторий на GitHub и свяжем его с локальным:

git remote add origin https://github.com/yourusername/my-lambda-app.git git push -u origin master

Теперь код доступен в удалённом репозитории, и можно настроить автоматизацию на основе изменений в нём.

Настройка CodeBuild

CodeBuild будет отвечать за сборку и тестирование приложения.

Создадим файл buildspec.yml в корне проекта со следующим содержанием:

version: 0.2  phases:   install:     runtime-versions:       python: 3.8     commands:       - pip install aws-sam-cli   pre_build:     commands:       - pip install -r hello_world/requirements.txt       - pip install -r tests/requirements.txt       - python -m pytest tests/unit -v       - sam validate --template template.yaml   build:     commands:       - sam build   post_build:     commands:       - sam package --s3-bucket my-lambda-artifacts-bucket --output-template-file packaged.yaml  artifacts:   files:     - packaged.yaml

В файле tests/unit/test_handler.py добавляем:

import json from hello_world import app  def test_lambda_handler():     event = {}     context = {}     response = app.lambda_handler(event, context)     data = json.loads(response['body'])     assert response['statusCode'] == 200     assert data['message'] == 'Hello, World!'

Это простой тест, который проверяет корректность ответа функции.

Создадим файл tests/requirements.txt и добавим:

pytest

Это необходимо для установки pytest на этапе сборки.

Настройка CodePipeline

Теперь настроим сам пайплайн, который будет автоматизировать процесс от коммита до деплоя.

Переходим в консоль AWS CodePipeline и создаём новый пайплайн.

Шаги настройки:

  1. Pipeline settings:

    • Name: MyLambdaPipeline.

    • Service role: создаём новую роль или используем существующую с необходимыми правами.

  2. Add source stage:

    • Source provider: GitHub.

    • Connect to GitHub: предоставляем доступ AWS к вашему репозиторию.

    • Repository: выбираем репозиторий my-lambda-app.

    • Branch: master.

  3. Add build stage:

    • Build provider: AWS CodeBuild.

    • Project configuration: создаём новый проект.

      • Environment:

        • Managed image: используем стандартный образ aws/codebuild/standard:5.0.

        • Runtime(s): Python 3.8.

      • Buildspec: используем buildspec.yml из репозитория.

  4. Add deploy stage:

    • Deploy provider: AWS CloudFormation.

    • Action mode: Create or update a stack.

    • Stack name: my-lambda-stack.

    • Template: packaged.yaml.

    • Capabilities: отметьте CAPABILITY_IAM.

После настройки пайплайна сохраняем его.

Сделаем изменение в коде, например, обновим сообщение в функции:

def lambda_handler(event, context):     message = "Hello, AWS Lambda!"     return {         'statusCode': 200,         'body': json.dumps({'message': message})     }

Закоммитим и запушим изменения:

git add . git commit -m "Updated message" git push origin master

Переходим в CodePipeline и убеждаемся, что пайплайн автоматически запустился и прошёл все этапы.

Управление конфигурацией и секретами

Для управления настройками и секретами рекомендуется использовать переменные окружения и сервисы AWS.

Обновим template.yaml, чтобы передавать переменные окружения в функции:

Globals:   Function:     Environment:       Variables:         STAGE: !Ref Stage  Parameters:   Stage:     Type: String     Default: dev

В коде функции можно получить переменную STAGE:

import os  def lambda_handler(event, context):     stage = os.environ.get('STAGE', 'dev')     message = f"Hello from {stage} stage!"     return {         'statusCode': 200,         'body': json.dumps({'message': message})     }

Теперь используем AWS Systems Manager Parameter Store для хранения секретов и конфиденциальных данных.

aws ssm put-parameter --name "/myapp/secret" --value "mysecretvalue" --type SecureString

Доступ к параметру в коде:

import boto3  def get_secret():     ssm = boto3.client('ssm')     parameter = ssm.get_parameter(Name='/myapp/secret', WithDecryption=True)     return parameter['Parameter']['Value']

Роль Lambda должна иметь права на ssm:GetParameter. Это можно сделать, добавив соответствующую политику к роли функции.

Мониторинг и логирование

Важно иметь возможность отслеживать работу функции и быстро находить ошибки.

В начале файла app.py добавим:

import logging  logger = logging.getLogger() logger.setLevel(logging.INFO)

Внутри функции используем:

def lambda_handler(event, context):     logger.info('Received event: %s', event)     # Основная логика

Это позволит записывать логи, которые можно просматривать в AWS CloudWatch.

Обновим template.yaml, чтобы включить X-Ray:

Globals:   Function:     Tracing: Active

AWS X-Ray позволяет собирать данные о производительности функции, создавать трассировки и визуализировать поток данных через приложение.

Обработка ошибок

Оборачивайте важные части кода в блоки try-except для отлова исключений:

Globals:   Function:     Environment:       Variables:         STAGE: !Ref Stage  Parameters:   Stage:     Type: String     Default: dev

Это позволит записать ошибку в логи и, при необходимости, повторно вызвать функцию.

В template.yaml добавьте параметры повторного вызова:

import os  def lambda_handler(event, context):     stage = os.environ.get('STAGE', 'dev')     message = f"Hello from {stage} stage!"     return {         'statusCode': 200,         'body': json.dumps({'message': message})     }

Это позволит автоматом повторять выполнение функции в случае ошибок.


Заключение

Если у вас возникли вопросы или вы хотите поделиться своим опытом, пишите в комментариях.

Сегодня в 20:00 пройдет открытый урок «Mock интервью на позицию Cloud Solution Architect» — поговорим, как уверенно пройти все этапы интервью. Если актуально — записывайтесь на урок на странице курса «Cloud Solution Architecture».


ссылка на оригинал статьи https://habr.com/ru/articles/852328/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *