Serverless приложение с реализацией CI/CD на базе AWS и Bitbucket Pipelines

В статье рассказывается о развертывании Django приложения в облаке AWS с помощью Bitbucket Pipelines. Тем, кому интересна эта тема, добро пожаловать под кат.

image


Вперед, на мины!

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


Проект представляет собой типичное Django приложение. Единственное отличие — настройки приложения будут подтягиваться через переменные environment. Репозиторий проекта находится на битбакете. Чтобы создать аналогичное, устанавливаем requirements из списка:

zappa==0.45.1
django-rest-swagger==2.1.2
djangorestframework==3.7.3
django-filter==1.1.0
Django==2.0
psycopg2==2.7.3.2
django-storages==1.6.5


Как видим, типовой набор зависимостей для построения REST API и подключения PostgreSQL. Далее проходим по шагам создания типичного Django приложения. Добавляем в настройки проекта настройки подключения к базе и размещения статики на S3.

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

#####################################
# ENV VARIABLES
#####################################
RDS_DB_NAME = os.environ.get('RDS_DB_NAME')
RDS_USERNAME = os.environ.get('RDS_USERNAME')
RDS_PASSWORD = os.environ.get('RDS_PASSWORD')
RDS_HOSTNAME = os.environ.get('RDS_HOSTNAME')
RDS_PORT = os.environ.get('RDS_PORT')
S3_BUCKET = os.environ.get('S3_BUCKET')
#####################################


#####################################
# THIS SETTINGS CAN'T BE OVERRIDED  #
#####################################
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': RDS_DB_NAME,
        'USER': RDS_USERNAME,
        'PASSWORD': RDS_PASSWORD,
        'HOST': RDS_HOSTNAME,
        'PORT': RDS_PORT,
    }
}
AWS_STORAGE_BUCKET_NAME = S3_BUCKET
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME

STATIC_ROOT = 'static'
STATIC_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN


Zappa — фреймворк, упрощающий развертывание wsgi-приложения на базе API Gateway и Lambda. Под капотом имеет генератор Cloudformation темплейта и адаптер event’а Lambda в wsgi-запрос, что позволяет использовать классическую схему работы приложения. Последним штрихом добавляем зависимости для тестов

pytest==3.3.1
pylint==1.8.1
tox==2.9.1
pytest-django==3.1.2
docstringtest==0.3.0


и добавляем файлы конфигурации для tox, pylint и pytest

Конфигурация Zappa


Представляет собой JSON или YAML файл с набором переменных. В моем варианте хранится на скрытом в настройках Pipelines S3 бакете и копируется каждый раз при создании артефакта.
Приведу пример:

{
  "dev1": {
    "environment_variables": {
      "RDS_DB_NAME": "dbname",
      "RDS_USERNAME": "user",
      "RDS_PASSWORD": "pass",
      "RDS_HOSTNAME": "host",
      "RDS_PORT": "5432",
      "S3_BUCKET": "s3-bucket"
    },
    "aws_region": "us-east-1",
    "django_settings": "sample.settings",
    "project_name": "serverless",
    "runtime": "python3.6",
    "s3_bucket": "app-bucket",
    "domain":"example.com",
    "certificate_arn":""
  }
}


Все, что относится к настройкам проекта, прописано в environment_variables. За подробностями всего остального обратитесь к документации zappa

Конфигурация Bitbucket Pipelines


Тех, кто не знает, что это такое, отсылаю к другим моим статьям. Здесь же постараюсь подробно рассмотреть конфигурацию пайплайна. Для CI/CD я использую следующий shell-скрипт:

#!/bin/bash


setup () {
    echo  ------- SETUP -------
    apt-get update # required to install zip
    apt-get install -y zip
    pip install virtualenv
    virtualenv --python=python3 env
    source env/bin/activate
    pip install -r requirements.txt
    return $?
}


tests() {
    echo ------- TESTS -------
    pip install -r requirements-test.txt # for tests
    tox
    return $?
}

deploy() {
    echo ------- DEPLOY -------
    echo $1
    pip install awscli
    aws s3 cp s3://$CMDB/zappa_settings.json .
    zappa update $1 || zappa deploy $1
    zappa certify $1 --yes
    zappa manage $1 "migrate --noinput"
    zappa manage $1 "collectstatic --noinput"
    return $?
}

setup && test && deploy $1


Скрипт работает в типовом для bitbucket pipeline контейнере (image: python:3.6.1) на Debian. Pipeline позволяет использовать любой контейнер с DockerHub, но адаптация скрипта останется на Вашей совести.

Собственно конфигурация пайплайна выглядит следующим образом:

image: python:3.6.1

pipelines:
  tags:
    release-*:
      - step:
          caches:
            - pip
          script:
            - ./ci.sh prod1
  branches:
    master:
      - step:
          caches:
            - pip
          script:
            - ./ci.sh dev1


image указывает на контейнер, деплой продакшена производится по тегам, мастер бранч деплоится в dev1 окружение. Желающие могут самостоятельно добавить прогон тестов на остальные бранчи. Все просто.

После добавления файлов конфигурации осталось только настроить сам битбакет. Включаем pipelines и прописываем переменные окружения:

image

Все, теперь можно пушить в мастер, срезать теги и… в общем, отдайте репозиторий разработчикам, они знают, что с ним делать.

За кадром осталась тема шифрования секретов и использования Cloudfront, а также настройки RDS, ACM, IAM, Route53, но это уже выходит за рамки статьи. Желающие могут все это найти в документации AWS.

Еще раз ссылка на репозиторий

© Habrahabr.ru