Serverless приложение с реализацией CI/CD на базе AWS и Bitbucket Pipelines
В статье рассказывается о развертывании Django приложения в облаке AWS с помощью Bitbucket Pipelines. Тем, кому интересна эта тема, добро пожаловать под кат.
Вперед, на мины!
Создание каркаса приложения
Проект представляет собой типичное 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 и прописываем переменные окружения:
Все, теперь можно пушить в мастер, срезать теги и… в общем, отдайте репозиторий разработчикам, они знают, что с ним делать.
За кадром осталась тема шифрования секретов и использования Cloudfront, а также настройки RDS, ACM, IAM, Route53, но это уже выходит за рамки статьи. Желающие могут все это найти в документации AWS.
Еще раз ссылка на репозиторий