UTokyo Project Sprint 用の記事です。主に、Django Sprint で構築した方を想定して書かれています。
この記事では EB CLI は使用せずに、コンソールからデプロイします。
また、この記事の内容は一例で、もちろんアプリ内で使用するフレームワークや、ライブラリによって異なりますので、適宜自分のプロジェクトに対応させてください。
目次
requirements.txtの修正- Elastic Beanstalkのアプリケーションと環境を作成する
- データベースの設定を行う
- アプリケーションソースバンドルを準備する
- アプリケーションソースバンドルを作成する
0. requirements.txt の修正
requirements.txt の Django と mysqlclient のバージョンを以下のように書き換えてください。
...
Django>=2.1,<2.2
mysqlclient==1.3.12
...
1. Elastic Beanstalkのアプリケーションと環境を作成する
AWS マネジメントコンソール にログインしてください。
ただし、AWS Educate のアカウントからの場合はこの記事を参考にしてください。
Elastic Beanstalk を選び、Create Application からアプリケーションを作成します。
- アプリケーション情報 > アプリケーション名 : 自身のアプリ名
- アプリケーションタグ : 任意。
-
プラットフォーム : 今回は、プラットフォーム は
Python、プラットフォームのブランチ はPython 3.6 running on 64bit Amazon Linux、プラットフォームのバージョン は2.9.10を選択しました。 - アプリケーションコード : とりあえず「サンプルアプリケーション」を選んでおきます。あとから自分のソースをアップロードします。
[アプリケーションの作成] を押します。あとは自動で環境まで作成してくれるので数分待っておきます。
無事終了したら、その環境のダッシュボードのような画面になると思います。左のメニューの、「環境に移動する」をクリックするとサンプルアプリケーションの画面が出てきます。
出てきたURLの http:// などの部分を除く XXX.YYY.ZZZ.elasticbeanstalk.com が自身のアプリのドメインになります。
あとでこれを使うので控えておいてください。
2. データベースの設定を行う
左のメニューから 設定 を選びます。一番下の データベース の右の 編集 ボタンを押します。
データベース設定 の各欄について以下の選択をします。Amazon RDS DB に作成されます。
-
エンジン :
mysql -
エンジンバージョン :
5.7.22を選択 -
インスタンスクラス :
db.t2.microを選択 -
ストレージ :
5 - ユーザー名 : 各自作成して(一応)覚えておいてください。
- パスワード : 各自作成して(一応)覚えておいてください。
-
保持期間 :
スナップショットの作成 -
アベイラビリティー :
低(1つのAZ)
[適用] を押してください。変更が反映されるまで待っておいてください。
3. アプリケーションソースバンドルを準備する
ここから主にローカルでの作業に移ります。以下、cms というアプリを作成している前提で進めているで、適宜自分のアプリ名に置き換えてください。
最初に、このセクションをすべて終えたときに出来上がるディレクトリ構造の一例を以下に示します。適宜参考にしてください。
├─ .ebextensions # Added
│ └─ python.config # Added
├─ requirements.txt
├─ manage.py # Updated
├─ cms
│ ├─ management # Added
│ | ├─ commands # Added
| | | ├─ createsu.py # Added
| | | └─ __init__.py # Added
| | └─ __init__.py # Added
│ ├─ templates
| ︙
│ └─ views.py
├─ config
│ ├─ __init__.py
│ ├─ settings # Added (settings.py removed)
| | ├─ common.py # Added
| | ├─ local.py # Added
| | └─ production.py # Added
│ ├─ urls.py
│ └─ wsgi.py # Updated
├─ docker-compose.yml
└─ Dockerfile
3-1. .ebextensions ディレクトリを作成する
Elastic Beanstalk にデプロイする際に必要となるディレクトリです。
プロジェクトのディレクトリ直下に .ebextensions ディレクトリを作成し、その中に python.config というファイルを作成してください。そのファイルに、以下を書き込んでください。一例なので、適宜書き換えてください。
なお、このファイルのインデントはtabだとエラーが出るので必ずspaceを使用してください。(コピペするとtabになると思うので、spaceに直してください。)
container_commands:
01_migrate:
command: 'python manage.py migrate'
leader_only: true
02_collectstatic:
command: 'python manage.py collectstatic --noinput'
03_createsu:
command: 'python manage.py createsu'
leader_only: true
option_settings:
'aws:elasticbeanstalk:application:environment':
DJANGO_SETTINGS_MODULE: 'config.settings.production'
PYTHONPATH: '$PYTHONPATH'
'aws:elasticbeanstalk:container:python':
StaticFiles: '/static/=www/static/'
WSGIPath: 'config/wsgi.py'
以下、上記の内容の解説です。
3-1-1. container_commands
01_migrate ではマイグレーション
02_collectstatic 静的ファイルの処理
03_createsu スーパーユーザーの作成
のコマンドを実行しています。なお、03_createsu の python manage.py createsu については後述します。
3-1-2. option_settings
DJANGO_SETTINGS_MODULE の部分で、後ほど作成する、 production.py を読み込むように環境変数を設定しています。
WSGIPath や StaticFiles などについては、コンソールの設定のところでも変更可能です。
option_settings について詳しく知りたい方は、以下を参照してください。
3-2. settings.py を分割する
次に、/config/settings.py を、開発用(Local)と本番用(Production)に分割します。
/config/settings.py は、Local 環境と Production 環境で別々のものを読み込む必要があるのですが、毎回書き換えていると大変なので、自動で切り替わるようにします。
具体的には、
-
common.pyに Local 環境と Production 環境で共通の設定項目を書き込む -
local.pyは、common.pyの内容に加えて、Local 環境固有の設定項目を書き込む -
production.pyは、common.pyの内容に加えて、Production 環境固有の設定項目を書き込む -
manage.pyとwsgi.pyを修正する
どちらの環境にも共通している設定項目は、 common.py に書き込みます。
個別に設定すべき内容
Local 環境と Production 環境でそれぞれ固有の設定は例えば以下のようなものです。
DEBUGDATABASEALLOWED_HOSTSMEDIA_ROOTSTATIC_ROOTLOGGING
ただし、common.py に書いている設定項目に、local.py や production.py で追加したい場合は、例えば以下のようにします。(配列に追加)
INSTALLED_APPS += (
'django.contrib.admin',
)
3-2-1. common.py, local.py, production.py を作成する
まず、 /config 直下に、 settings というディレクトリを作成し、その中に /config 下の settings.py を移動させ、 common.py にリネームしてください。
また、 /config/settings ディレクトリの中に local.py, production.py の2つのファイルを新規に作成してください。
以下のようなディレクトリ構造になっていることを確認してください。
...
├─ config
│ ├─ settings # Added
| | ├─ common.py # Added (settings.py をリネームしたもの)
| | ├─ local.py # Added
| | └─ production.py # Added
...
3-2-2. BASE_DIR を修正する
common.py の最初のほうにある BASE_DIR を以下のように変更してください。
...
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
...
↓
...
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
...
3-2-3. local.py にLocal 環境固有の設定を書き込む
local.py に、 common.py の内容に加えて、Local 環境で固有の設定項目を書き込みます。
common.py の内容を以下のようにimportします。
from .common import *
あとは、個別に設定すべき内容 を書けばよいだけです。
これを踏まえると、 local.py は例えば以下のようになります。
これはローカルでPostgreSQLを使っていた場合なのですが、各自ローカルで使っていたDBの設定をそのまま移していただいて結構です。
from .common import *
DEBUG = True
ALLOWED_HOSTS = [
'0.0.0.0',
'127.0.0.1',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
'PASSWORD': 'somepassword',
}
}
3-2-3. production.py にProduction 環境固有の設定を書き込む
production.py に、 common.py の内容に加えて、Production 環境で固有の設定項目を書き込みます。
local.py と同様に、 common.py の内容を以下のようにimportします。
from .common import *
あとは、個別に設定すべき内容 を書けばよいだけです。以下の項目は一例です。自身の環境に合わせて、適宜対応してください。
3-2-3-1. DEBUG
Production 環境では、DEBUG を FALSE にします。
...
DEBUG = False
3-2-3-2. ALLOWED_HOSTS
ALLOWED_HOSTS に自身のアプリのドメインを追加します。ただし、 XXX.YYY.ZZZ.elasticbeanstalk.com の部分は1で確認した自分のアプリのドメインに置き換えてください。
...
ALLOWED_HOSTS = [
'XXX.YYY.ZZZ.elasticbeanstalk.com',
]
3-2-3-3. DATABASES
DATABASES を、本番環境の RDS のものに書き換えます。 'RDS_~' という変数を使えば、Elastic Beanstalk のほうで勝手に書き換えてくれます。
'ENGINE' が local.py とは変わっていることに注意してください。
...
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'],
}
}
3-2-3-4. STATIC_ROOT
STATIC_ROOT を追加します。
...
STATIC_ROOT = os.path.join(BASE_DIR, 'www', 'static')
以上を踏まえると、全体として production.py は例えば以下のようになります。ただし、 XXX.YYY.ZZZ.elasticbeanstalk.com の部分は1で確認した自分のアプリのドメインに置き換えてください。
from .common import *
DEBUG = False
ALLOWED_HOSTS = [
'XXX.YYY.ZZZ.elasticbeanstalk.com',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'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'],
}
}
STATIC_ROOT = os.path.join(BASE_DIR, 'www', 'static')
3-2-5. common.py を修正する
common.py の、Local 環境とProduction 環境に 個別に設定すべき内容 の項目とその値(中身)をすべて削除してください。
例えば今回であれば、 DEBUG、ALLOWED_HOSTS、DATABASES などが該当します。
3-2-6. common.py に STATIC_URL を追加する
common.py に以下を追記します。すでにある場合は飛ばして構いません。
...
STATIC_URL = '/static/'
...
なお、Djangoの静的ファイルの扱いについては、この記事がとても分かりやすいので、是非読んでみてください。
3-2-7. manage.py と wsgi.py を修正する
ルート直下の manage.py と、/config 直下の wsgi.py の以下の部分を修正します。
...
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
...
↓
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
...
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
...
3-3. スーパーユーザー作成用のコマンドを準備する
最後に、スーパーユーザー作成用のファイルを作成していきます。スーパーユーザーの作成は、Local 環境であれば、
$ python manage.py createsuperuser
などとして、ユーザー名、メールアドレス、パスワードを入力したと思いますが、今回はサーバーに実行してもらうため、それらを手動で入力することができません。なので、事前に入力する値を設定しておいて、それを実行させます。それが前述の 3-1-2 で出てきたものです。
3-3-1. createsu.py を作成する
cms(アプリ名なので置き換えてください。)の下に management フォルダ、その下に commands フォルダを作成し、そこに createsu.py を作成してください。そのファイルに以下を書き込んでください。
8行目の XXX、9行目の XXX、YYY、ZZZ は各自で書き換えて、どこかに控えておいてください。また、8行目の XXX と 9行目の XXX は一致させてください。
これがスーパーユーザーアカウントになります。複数作りたい場合は、 if 文の数を増やせばよいだけです。
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth import get_user_model
User = get_user_model()
class Command(BaseCommand):
def handle(self, *args, **options):
if not User.objects.filter(username="XXX").exists():
User.objects.create_superuser(username="XXX", email="YYY", password="ZZZ")
self.stdout.write(self.style.SUCCESS('Successfully created new super user'))
3-3-2. __init__.py を作成する
次に、作成した management, commands フォルダそれぞれの直下に __init__.py というファイルを作成してください。これらのファイルは作成するだけで、中身は何も書き込みません。
これで「アプリケーションソースバンドルの準備」は完了です。このセクションの最初にお見せした、ディレクトリ構造と同じようになっているかどうかを確認してください!
4. アプリケーションソースバンドルを作成する
あとは、作成したものを zip にして、デプロイするだけです。
4-1. zip ファイルを作成する
何も難しいことはないかと思いますが、 zip にする対象について。
基本的にプロジェクト直下のファイル、フォルダをまとめて zip にします。(プロジェクトのディレクトリそのものを zip にするわけではない)
ただし、例えば git を使っているのなら、 .git フォルダや、 .gitignore などのファイルがあると思いますが、**それらは含めません。**アプリケーションに必要なものだけを対象にしてください。
必要であれば以下を参照してください
Mac, Linux の場合
例えばプロジェクトのルートディレクトリで、以下のようなを実行すれば、プロジェクトの一つ上の階層に myapp.zip が生成されます。( . から始まるものは、 .ebextensions しか含まれないので、ほかに含める必要のあるファイルやフォルダがあれば適宜対応してください。)
$ zip ../myapp.zip -r * .ebextensions
Windowsの場合
コマンドプロンプトやPowershellからもできますが、コマンドが長すぎるのと、含めないファイル(フォルダ)の設定がややこしいのでGUIでやります。以下のように、必要なファイルとフォルダを選択して、
右クリック→送る→圧縮(zip形式)フォルダー
とすれば作成できます。
4-2. アップロードしてデプロイする
いよいよ、サーバーにアップロードしてデプロイします。
コンソールの実行バージョンの下の、「アップロードとデプロイ」をクリックして、先ほど作成した zip ファイルを選択します。
バージョンラベルは自分でバージョンを区別できるわかりやすいものを付けると良いでしょう。
あとは、「デプロイ」ボタンを押して完了です。
最初のデプロイは完了までに数分かかることがあるので辛抱強く待ってください。
エラーが出ていなければデプロイ完了です。自身のアプリのURLにアクセスして、スーパーユーザーアカウントにログインできるか、などを確認してみましょう。
以上です。お疲れさまでした。
参考
- データベースを Elastic Beanstalk 環境に追加する
- Python アプリケーション環境に Amazon RDS DB インスタンスを追加
- アプリケーションソースバンドルを作成する
- Tutorial: Deploying Python 3, Django, PostgreSQL to AWS Elastic Beanstalk
- Deploying Django + Python 3 + PostgreSQL to AWS Elastic Beanstalk
- [Django] プロジェクト構成のベストプラクティスを探る - 2.設定ファイルを本番用と開発用に分割する
- Elastic Beanstalk Python プラットフォームを使用する
- Djangoにおける静的ファイル(static file)の取り扱い
