Amazon Web Services допомагає розгортати додатки без необхідності вручну налаштовувати систему. EC2-екземпляр, на якому буде працювати додаток, не потрібно створювати та налаштовувати вручну. Це стає можливим завдяки інструменту Elastic Beanstalk (EB).
Beanstalk також може забезпечити балансування навантаження: так само “моментально” — як при деплої.
Я подумав, що буде непогано описати процес деплою нового сайту на Python/Django з базою даних, S3 для статичних файлів, доменом і SSL-сертифікатом.
Початкові вимоги
Я використовую Linux Ubuntu 16.04 локально, а розгортатиму простенький Django-додаток під Amazon Linux (Red Hat). Для роботи відкриті Terminal, PyCharm і Firefox з AWS Console. Нам знадобляться встановлені git
і python3
, активований акаунт AWS і який-небудь блокнот.
Якщо акаунту AWS доступний Free tier і ще немає жодної бази MySQL/Postgres/Mariadb (RDS) і немає EC2-екземплярів t2.micro,
додаток може обходитися абсолютно безкоштовно в межах Free tier, поки ми не вирішимо використовувати балансувальник навантаження, доменне ім'я/SSL, де Free tier не вистачить.
Створення проекту
Замість класичного способу з django-admin startproject
я користуюсь своїм скриптом, який додатково створює віртуальне середовище (virtualenv) для майбутнього проекту і патчить конфігурацію для готовності до деплою на Beanstalk. Скрипт у моєму випадку збережений як ~/django-start.sh
:
cd ~/Projects
~/django-start.sh mydjango python3
До речі, можна обійтися без virtualenv; командою
django-admin startproject mydjango
для створення проекту. При деплої ми передаємо список залежностей PIP (requirements.txt), локально вони встановлюються в "віртуальне" середовище, щоб не зачіпати іншу систему розробника.
На самому ділі можна працювати без virtualenv і папки venv, Beanstalk при деплої налаштовує своє віртуальне середовище автоматично (читаючи requirements.txt). У такому випадку достатньо додати файл
requirements.txt
з однією строкою — типу
Django==1.11.7
Підказка: скрипт
django-start.sh
за посиланням вище — виконує деякі дії, описані в цій статті — патчsettings.py
і додавання потрібних.ebextensions
, але працювати він буде тільки на ubuntu linux, та й додаток “website” всередині проекту доведеться створити вручну — тому я описую всі потрібні дії вручну.
Після створення проекту, створюємо всередині додаток website:
cd mydjango
source venv/bin/activate
django-admin startapp website
У файлі mydjango/mydjango/settings.py
потрібно додати "website"
в кінець списку INSTALLED_APPS
.
Комітимо результат:
git init
git add .
git commit -m"Initial django project and app!"
Якщо є віддалений Git-репозиторій, куди потрібно записати проект, додаємо URL і пушимо (у моєму випадку з повним перезаписом репозиторію):
git remote add origin
git push --force --set-upstream origin master
Але для Elastic Beanstalk достатньо локального репозиторію.
Elastic Beanstalk CLI
Розгорнемо додаток одразу в поточному вигляді на AWS за допомогою Elasticbeanstalk (EB). Для цього будемо використовувати інструмент командного рядка, який встановлюється з PIP.
(deactivate; pip3 install awsebcli)
eb init
(deactivate; pip3 install …)
— тут для того, щоб встановити AWS EB-CLI поза активним середовищем, оскільки в самому проекті “eb” не потрібно, логічно?
Для успішної ініціалізації додатка знадобиться в інтерактивному режимі вказати параметри доступу до акаунту AWS. Насамперед, використовуваний дата-центр (більш точний термін — region).
В моєму випадку це був us-east-2
, який можна побачити в адресному рядку браузера при вході в акаунт:
https://.console.aws.amazon.com/
Щоб отримати необхідні токени доступу, які будуть запитуватись командою, потрібно в консолі AWS відкрити сторінку “IAM”.
Тут необхідно додати групу, наприклад, “root”, і до неї додати користувача, наприклад, “root-cli”. При створенні користувача потрібно вказати, що це користувач командного рядка, а не користувач AWS Console (сайту). З цим питанням з'явиться спеціальне спливаюче вікно.
У групи, до якої буде додано користувача, потрібно встановити (додати) права доступу, інакше жодні дії за допомогою “eb ..” виконати не вдасться. У моєму випадку права групи були додані наступні:
На сторінці налаштувань групи є вкладка для конфігурації прав доступу
На сторінці налаштувань користувача можна знайти кнопку “Create access key”
Отримуємо необхідні для eb init
токени доступу — вони показуються лише один раз. Їх потрібно вказати команді eb init
.
Тепер користувачі цієї групи можуть, зокрема, розгортати додатки в Beanstalk.
На одному з етапів буде задано питання про CodeCommit. Відповідаємо стандартне N (no):
Do you wish to continue with CodeCommit? (y/N) (default is n): n
На іншому етапі програма запитає, чи потрібно додавати SSH-ключ на створюваний для деплою EC2-екземпляр, і який ключ використовувати. Ключі SSH конфігуруються в розділі IAM консолі AWS. Доступ до екземпляра по SSH в більшості випадків не потрібен: саме для абстракції від ОС і її налаштувань Beanstalk і існує. Хоча може знадобитись скачувати якісь файли, наприклад, для чого SSH буде в самий раз.
Platform / version
eb init
запропонує вибрати платформу для додатку (при створенні):
It appears you are using Python. Is this correct?
(Y/n): ySelect a platform version.
1) Python 3.4 (Preconfigured - Docker)
2) Python 3.4
3) Python
4) Python 2.7
(default is 1): 1
“Select a platform version” — тут вибирається платформа. При цьому можна створювати свої платформи, про що можна прочитати в документації AWS по продукту CloudFormation, який Beanstalk використовує під капотом.
Цього разу ми повинні вибрати відповідь “Python 3.4” (важливо, що без Docker). Якби у нас в папці знаходились файли з кодом на PHP, або Ruby, наприклад, нам були б запропоновані відповідні варіанти. Також можна вибрати планований stack/мова флагом -p php
і т.п.
Environments
Оточення — це запущений і сконфігурований потрібним чином додаток. Наприклад, можна створити два різних оточення одного додатку, перше буде для однієї категорії користувачів, друге — для іншої (prod vs. devtest). У них можуть бути різні параметри Security groups (firewall) і т. д.
Створюємо оточення командою:
eb create -s
Їй знадобиться ім'я для оточення — я залишив автоматичне (“mydjango-dev”), і CNAME: префікс для доменного імені, за яким буде доступний додаток в мережі, який я також залишив за замовчуванням.
Параметр
-s
вказує Beanstalk створити single-instance оточення, точніше — без балансувальника навантаження (load balancer). Це важливо, оскільки в AWS немає безкоштовного режиму для користування балансувальниками, а ми хочемо для free tier вкластися рівно в 1 інстанс EC2 малої потужності, цього разу.
Без параметра -s в оточеннях будуть створюватися балансувальники.
Нормально: додаток (“mydjango”) і створене оточення (“mydjango-dev”) можна побачити в консолі AWS.
Якщо потрібно використовувати вже існуюче оточення, а не створювати нове, є команда
eb use mydjango-dev
(наприклад).
.ebextensions
Необхідно в корені проекту створити папку з зарезервованим ім'ям .ebextensions
. В ній — файл django.config
з вмістом (YAML-файл):
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python manage.py migrate --noinput"
leader_only: true
02_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python manage.py collectstatic --noinput"
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "mydjango.settings"
"PYTHONPATH": "/opt/python/current/app/mydjango:$PYTHONPATH"
"aws:elasticbeanstalk:container:python":
WSGIPath: mydjango/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "static/"
Можна знайти багато цікавих постів про те, як писати такі конфігураційні файли для різних цілей (раз, два, три, …).
Як не складно здогадатися, файли в цій папці служать конфігурацією при створенні екземпляра EC2, на якому буде працювати додаток. Можна додавати в container_commands
різні команди, які виконуються в алфавітному порядку, все, що потрібно додатку при деплої.
Додаємо цю папку в git:
git add .ebextensions
git commit -m"Add .ebextensions"
Щоб не виникало помилок в додатку, потрібно виправити settings.py
:
ALLOWED_HOSTS = ['..elasticbeanstalk.com']
STATIC_ROOT = os.path.join(BASE_DIR, 'static') # важливо
Можна використовувати ALLOWED_HOSTS=[*]
, або ALLOWED_HOSTS=[".elasticbeanstalk.com"]
, або все-таки написати CNAME і ім'я дата-центра, подивившись його в консолі Beanstalk:
Готово нарешті. Можна розгортатись:
git add mydjango/settings.py
git commit -m"Add allowed_hosts"
eb deploy
EB знає про локальний git-репозиторій. Насправді завантажуються файли з останнього коміту на поточній гілці. Тобто, якщо ми робимо якісь зміни, ми обов'язково повинні додати файли в репозиторій, зробити
git commit
і тільки потімeb deploy
.
Куди-небудь відправляти правки за допомогоюgit push
не потрібно.
Відповідно,.ebextensions
,requirements.txt
і всі такі файли повинні бути під версійним контролем.
Структура файлів (локально)
Додаток працює в Amazon cloud. Можна користуватись — хоч і з довгим доменом
Хмарні бази даних
На даний момент наше додаток і в хмарі, і локально використовує базу даних SQLite (файл).
Навіть починати заповнювати реальну базу даних майбутнього сайту на SQLite не варто, оскільки перенесення на MySQL буде зовсім не простим.
Спробуємо використовувати базу даних, створену за допомогою Amazon RDS. Для цього відкриваємо консоль RDS -> Launch New Instance.
Одну базу Amazon дає безкоштовно (free tier):
20 ГБ для першої бази надаються безкоштовно (free tier)
Я використовую MariaDB, оскільки MySQL розвивається значно повільніше; MariaDB — це сумісний з MySQL-клієнтами форк MySQL Server.
Пропонується ID бази даних у консолі AWS, username/password для бази.
Public Access для бази можна вимкнути, налаштувавши пізніше security group вручну.
На наступній сторінці можна буде вибрати для бази Security group, ім’я бази даних і порт бази даних.
Підключення до баз у RDS зашифровані за допомогою TLS-сертифікатів Amazon RDS CA.
Бесцінно.
Конфігурація Django для RDS
Запишемо в налаштуваннях проекту конфігурацію бази даних MySQL, яка вже має працювати (процес створення бази розглянемо пізніше).
Це робиться просто — параметри підключення будуть передаватися додатку Beanstalk за допомогою змінних середовища (os.environ
).
У файлі mydjango/settings.py
необхідно після стандартного визначення DATABASES
додати код, який підтягує значення з змінних:
# AWS RDS (якщо розгортається через Beanstalk)
if 'RDS_HOSTNAME' in os.environ:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ['RDS_DB_NAME'],
'USER': os.environ['RDS_USERNAME'],
'PASSWORD': os.environ['RDS_PASSWORD'],
'HOST': os.environ['RDS_HOSTNAME'],
'PORT': os.environ['RDS_PORT'],
}
}
Додаток може використовувати локально SQLite, оскільки жодного RDS_HOSTNAME
тут не буде (Підказка: насправді не слід використовувати SQLite навіть локально). Або ж можна змінити первинне визначення DATABASES
, яке буде використовуватись при запуску без Beanstalk.
Перевірити працездатність можна, виконавши стандартні команди:
./manage.py migrate
./manage.py createsuperuser
./manage.py runserver 8000
Тест конфігурації для RDS
Оновимо код нашого додатку так, щоб на головній сторінці показувався використовуваний у цей момент DB Backend (mysql чи sqlite). mydjango/website/views.py
:
from django.db import connection
from django.http import HttpResponse
_# Create your views here._
def home_view(request):
return HttpResponse(content="Database vendor is %s." % connection.vendor)
mydjango/mydjango/urls.py
:
from django.conf.urls import url
from django.contrib import admin
from website import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url('^$', views.home_view)
]
./manage.py runserver 8000
:
В консолі AWS, відкриваємо Software Configuration в налаштуваннях додатку Beanstalk:
В нижній частині сторінки знайдемо Environment Variables — тут можна задати ті самі змінні середовища, які Django отримує в os.environ
, поряд з PYTHONPATH
і DJANGO_SETTINGS_MODULE
, які Beanstalk додає автоматично.
Щоб додати налаштування RDS, потрібно подивитися дані на сторінці інстанса RDS (клікнувши на ім'я інстанса з базою). У досить завантаженому dashboard можна буде знайти Endpoint (RDS_HOSTNAME
) бази, порт і Username для доступу. Після збереження змін середовище буде оновлено (перезапущено), але ще дещо потрібно додати, щоб запрацювало.
В кінець файлу requirements.txt
додаємо рядок:
mysqlclient==1.3.12
Не потрібно прописувати встановлення додаткових системних пакетів для підтримки MySQL на стороні EC2/Beanstalk.
Хоча установку пакетів APT/RPM/YUM можна додати в конфігураційний файлdjango.config
, по-видимому, в Amazon Linux (образ ОС, який використовується в нашому випадку) таких пакетів просто немає (я пробував yum-пакетиpython3-dev
іmysql-python3
), але виявилося, що це просто не потрібно.
Необхідно зберегти конфігурацію додатка і почекати кілька хвилин (поки оточення буде збережене). Потім, розгорнути нову версію Beanstalk:
source venv/bin/activate
pip3 install -r requirements.txt
git add mydjango website .ebextensions requirements.txt
git commit -m"Database backend test"
eb deploy
Додаток використовує MySQL
Перевірити, що підключення дійсно працює — лише створивши які-небудь моделі та спробувавши зробити деплой після makemigrations
.
Коли не вдається підключитись до своєї бази, потрібно перевірити прив’язану до неї Security Group: чи не фільтруються Inbound порти/IP-адреси?
Якщо security-групу створював RDS, в її правилах буде дозволено доступ тільки для машин в тому ж хмарі (VPC). У моєму випадку це чомусь не працювало, довелося відкрити доступ до бази по IP-адресі EC2-екземпляра, створеного Beanstalk. Зробити це потрібно для групи безпеки, під якою працює база RDS, в секції Inbound Rules, дозволивши TCP-порт 3306.
Далі — про домени, балансувальники, SSL і статичні файли:
[
Elastic Beanstalk з Django, ч. 2
Підключаємо домен
medium.com
](/@infra9/elastic-beanstalk-ч-2-7f2d2d9e5cf4?source=post_page-----99804942b549--------------------------------)
Перекладено з: Elastic Beanstalk с Django, ч.1