CI/CD-пайплайны автоматизируют процессы создания, тестирования и развертывания программного обеспечения, позволяя командам быстро и надежно выпускать обновления. В этой статье рассмотрим, как создать пайплайн с помощью AWS, как использовать CodeBuild для запуска при размещении кода в ветке. Также разберем, как запускать тесты, затем собирать и размещать образ Docker в ECR, и сохранять артефакты кода в S3, после чего можно использовать функцию Lambda для запуска CodeDeploy, которая развернет код на группе EC2-инстансов.

Почему бы просто не использовать CodePipeline?! Ответ - не везде это возможно.

А что, если я собираюсь отправлять образы в ECR, то зачем использовать CodeDeploy для отправки кода в EC2-инстансы? В некоторых случаях вы не сможете получить код из частного хранилища в ECR.

Вот схематический обзор того, что мы будем делать: 

Наш код

Для примера я собираюсь использовать простое приложение на Python для создания API с помощью flask

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, Docker!"

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=80)

Тесты важны для кода: в случае неудачи мы не развернем в продакшене код с ошибками.

# tests/test_app.py
from app import app

def test_index_route_success_status():
    response = app.test_client().get('/')
    assert response.status_code == 200
    
def test_index_route_success_text():
    response = app.test_client().get('/')
    assert response.data.decode('utf-8') == 'Hello, Docker!'

И, наконец, мы пишем Dockerfile

# Dockerfile
FROM python:3.8-slim

# Set the working directory in the container
WORKDIR /app

# Install the dependencies
RUN pip install flask pytest

# Copy the application code to the container
COPY . .

# Set the command to run the application
CMD ["python", "app.py"]

Теперь наш код готов к переносу в основную ветку и развертыванию.

CodeBuild

Теперь откройте AWS CodeBuild и создайте проект для построения, добавьте имя проекта и источник кода — bitBucket в нашем примере — и ветку, которую необходимо считывать. Включите webhooks.

И в разделе «Окружение» необходимо включить привилегированный режим, поскольку мы хотим собирать Docker-образы.

И если мы хотим передать информацию в процесс сборки, мы можем использовать переменные среды. Здесь мы должны передать несколько значений: 


AWS_DEFAULT_REGION: регион, который вы используете

IMAGE_TAG: тег для образа Docker

IMAGE_REPO_NAME: имя репозитория ECR

AWS_ACCOUNT_ID: идентификатор учетной записи пользователя

Эти значения могут быть вставлены в buildspec.yml напрямую, но в целях безопасности лучше использовать переменную среды. Файл buildspec.yml очень важен, мы обсудим его после части, посвященной артефактам.

В артефактах мы выберем S3, затем выберем хранилище, куда мы хотим их отправить. Артефакты должны быть в формате Zip.

buildspec.yml

Этот файл указывает CodeBuild, что делать, когда код будет загружен. Вы можете создать пошаговое описание, оно должен находиться в корневой папке проекта.

#buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
       - echo Logging in to Amazon ECR...
       - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo run tests first
      - pip install flask pytest
      - python3 -m pytest --junitxml=/usr/tests/test-report.xml
      - echo Build started on `date`
      - echo Building the Docker image...          
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG 
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      
Reports:
  pytest-reports:
    files:
      - test-report.xml
    base-directory: /usr/tests/
    file-format: JUNITXML

Artifacts:
  type: zip
  files:
    - '**/*'

На этапе pre_build мы вошли в нашу учетную запись ECR

На этапе сборки мы запустили тест, сохранили результат в файл и собрали образ

На этапе post_build мы поместили docker в хранилище.

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

Отчеты будут отображать результат нашего тестирования в CodeBuild позже, вот ссылка для более подробной информации об отчете

Артефакты:

CodeDeploy

Создайте приложение и затем создайте группу для развертывания. Развернем для одного инстанса EC2 с тегом «env» и значением «dev».

И отключите функцию балансировки нагрузки, в этом случае она нам не нужна. Лучше установить Codedeploy вручную.

Для работы CodeDeploy необходимо написать шаги, что делать, когда инстанс в установочной группе получает код. Эти шаги записываются в appspec.yml, файл также должен располагаться в корневой директорий проекта.

appspec.yml
version: 0.0
os: linux
# this to copy all files in the project to spacfic location
files:
  - source: /
    destination: /usr/src/app/
# overrite file if they are already there
file_exists_behavior: OVERWRITE

hooks:
  BeforeInstall:
    - location: scripts/before_install.sh
      runas: root
  ApplicationStart:
    - location: scripts/application_start.sh
      runas: root

Hook — это элементы конфигурации, используемые в AWS CodeDeploy для того чтобы определить действия, которые должны быть выполнены до и после развертывания, например, запуск скриптов или выполнение команд.

#scripts/before_install.sh

#stop all running containers
docker kill $(docker ps -q)

#delete all images
docker rmi -f $(docker images -aq)

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

#scripts/application_start.sh

# build the docker image
docker build -f /usr/src/app/Dockerfile /usr/src/app/ -t myapp

# run the container
docker run -d -p 80:80 myapp

В запуске приложения мы собираем наш образ и затем запускаем его на порту 80

*CodeDpoly должен быть установлен на целевом инстансе EC2. Иногда он не подключается, так что вам придется перезапустить процесс или весь инстанс.

Вот окончательная структура нашего проекта:

Lambda Functions

Необходимо используем эту функцию для  развертывания всякий раз, когда CodeBuild размещает новые артефакты в S3. Можно использовать Python и библиотеку boto3, которая позволяет писать программное обеспечение, использующее такие сервисы, как Amazon S3 и Amazon EC2.

import boto3

def lambda_handler(event, context):
    # Get the S3 bucket and object information from the event
    s3_bucket = event['Records'][0]['s3']['bucket']['name']
    s3_key = event['Records'][0]['s3']['object']['key']

    # Create a CodeDeploy client
    codedeploy_client = boto3.client('codedeploy')

    # Create a deployment with the S3 revision
    response = codedeploy_client.create_deployment(
        applicationName='codedeply-ec2',            #change this to codedepoly application name
        deploymentGroupName='codedeploy-ec2',       #change this to deployment group name
        revision={
            'revisionType': 'S3',
            's3Location': {
                'bucket': s3_bucket,
                'key': s3_key,
                'bundleType': 'zip'
            }
        }
    )

    # Print the deployment ID
    deployment_id = response['deploymentId']
    print(f"Deployment ID: {deployment_id}")
От редакции

Возможности CI/CD позволяют специалистам автоматизировать процессы интеграции и регулярно выпускать ПО высокого качества. На курсе «CI/CD на примере Gitlab CI» мы учим принципам CI/CD: конвейерному методу разработки, работе с пайплайнами, билдами и артефактами. Узнать больше о программе и записаться на курс вы можете на нашем сайте: https://slurm.io/gitlab-ci-cd

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