Приветствую! Сегодня я расскажу вам, как настроить 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".

Комментарии (0)