Flask を AWS Elastic Beanstalk にデプロイする手順については 別記事 に書きました。この記事では Django を AWS Elastic Beanstalk にデプロイする手順について書きます。重複する部分も多いですが(特に前半)Flask を飛ばして Django を勉強する人もいるでしょうから敢えて再掲します。
Django も AWS EC2 にデプロイすることは可能です。実際、Ubuntuベースの当サイトで Djangoのデモ が動いています。 (サーバーを移設したためこのデモは現在動作しません。)EC2 で Linux ベースのインスタンスを立ち上げれば同じことが可能です。しかし、せっかく AWS を使うならメリットの大きい Elastic Beanstalk を使ってみましょう。
この記事では Djangoチュートリアル 等の学習を終え、ローカル環境で Django が使えることを前提に、そのアプリを AWS Elastic Beanstalk を使ってクラウドにデプロイします。AWSのアカウント登録やログインの方法は AWS(EC2)にデプロイする と同じです。この記事ではAWSにログインできることを前提に説明を開始します。
Elastic Beanstalk の公式ガイドはこちらです。
この記事は下記の公式ガイドのDjangoチュートリアルをベースに説明不足の部分を補足し、ハマリどころの解説を加えたものです。
アクセスキーを作成する
AWSにアカウント登録してそのまま使っている人は “ルートユーザー” としてサインインしていると思います。
これからWEBアプリをデプロイするのですがルートユーザーの権限でアプリを公開するのはセキュリティ面で好ましくありません。WEBアプリに必要な権限だけを与えたIAMユーザーを作成して、そのユーザー権限下でWEBアプリを動作させます。
AWSにログインしてメニュー検索から “IAM” を探してください。”Identify and Access Management (IAM)” というサービスに入ったら、左側のメニューから “ユーザー” を選択します。さらに “ユーザーを追加” のボタンを押してください。
“ユーザーを追加” のボタンを押すと新しいユーザーに関する設定画面になりますので順に設定します。設定画面は5つの段階で進みます。
(1) ユーザー詳細の設定
- “ユーザー名” は任意の名前で構いません。今回は Elastic Beanstalk に関する権限を与えるので “ebmaster” としました。
- “AWS認証情報タイプを選択” は、”アクセスキー・プログラムによるアクセス” を選択します。
- “次のステップ:アクセス権限” のボタンを押します。
(2) アクセス権限
ユーザーに許可するオペレーション内容を設定する重要な画面です。Elastic Beanstalk 公式ガイドに ユーザーポリシーについての解説 があるので従います。”既存のポリシーを直接アタッチ” のボタンを押して “ErasticBeanstalk” で検索すると “AdministratorAccess-AWSElasticBeanstalk” が出てくるので選択します。
【重要】Elastic Beanstalk はデプロイする時に EC2 も使います。従ってEC2に対する権限も必要です。”AmazonEC2FullAccess” というポリシーも追加しておいてください。忘れると、後の手順で権限が無いという趣旨のエラーが発生します。
(3) タグの追加(オプション)
この画面の設定項目はオプションなので、何もせず “次のステップ:確認” を押します。
(4) 確認
ここまで設定した内容が表示されるので、確認して “ユーザーの作成” を押します。
(5) アクセスキーの入手
“成功” と表示されて、作成したユーザーのアクセスキーが表示されます。アクセスキーとシークレットアクセスキーは後で使いますので、CSVファイルを保存してください。保存したCSVファイルは厳重に管理してください。
Python3.7 の環境を作る
Elastic Beanstalk に Django をデプロイするとき、Python3.8 以降を使うと SQLite とのバージョン不整合を起こしてエラーが発生します。Python3.8 以降ではDjango4 がインストールされますが、Django4 が要求する SQLite のバージョンが存在しないという内容です。回避策は SQLite 以外のデータベースを使うか、Python3.7 を使うかです。Python3.7 では Django3 がインストールされるので問題ありません。(Python3.8 で Django3 を使うという方法があるかもしれませんが未確認です。)
Djangoチュートリアル で Polls アプリを作ったときには Python のバージョンはあまり意識しませんでしたが、Python3.7 を使ってもう一度動作確認をしてください。Python3.7 の環境を作る方法を説明します。
virtualenv で仮想環境を作る時に Python のバージョンを指定することができます。
1 2 3 4 |
$ virtualenv -p python3.7 django $ source django/bin/activate (django) $ python3 -V Python 3.7.12 |
Windows のWSL環境ならこれでうまくいくと思います。ただし、virtualenv の -p オプションで指定できるのは既にインストールされている Python が存在している場合だけです。そもそも Python 3.7 がインストールされていなければ上記のコマンドはうまく動作しません。その場合は予め Python3.7 をインストールしてください。
Apple Silicon Mac の場合は、直接 Python3.7 をインストールするのは手順が煩雑なので pyenv を使うことにします。virtualenv は Python 仮想環境にインストールされるライブラリーを管理するツールですが、pyenv は Python そのもののバージョンを管理できます。もし pyenv がインストールされていなかったら次のコマンドでインストールします。
1 |
$ brew install pyenv |
インストールできたら pyenv を有効にするため、.zshrc に次の3行を追加します。もし bash を使っていたら .bash_profile に追加してください。
1 2 3 |
export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/shims:$PATH" eval "$(pyenv init -)" |
ターミナルソフトを再起動するか、”source ~/.zshrc” コマンドを実行すれば追加した内容が反映されます。次のコマンドで、pyenv でインストール可能なバージョンが一覧表示されます。その中で 3.7 の最終版が何か調べてください。
1 |
$ pyenv install --list |
筆者の環境では 3.7.12 だったので、これを pyenv でインストールします。
1 2 |
$ pyenv install 3.7.12 ←指定したバージョンのPythonがインストールされます。 $ pyenv versions ←pyenv配下にインストールされたPythonのバージョン一覧。3.7.12があればOK。 |
いつものように作業ディレクトリに移動して、virtualenv で仮想環境を作ります。
1 2 3 4 5 6 7 |
$ cd project ←作業ディレクトリに移動 $ pyenv local 3.7.12 ←作業ディレクトリ以下では3.7.12が動作するようになります。 $ python3 -V ←バージョンを確認 Python 3.7.12 $ virtualenv -p python3.7 django ←3.7の上に仮想環境を作ります。 $ source django/bin/activate (django) $ |
次にチュートリアルの復習をしますが、いま作った Python3.7 の環境で実行してください。
Django アプリの動作を再確認
デプロイするアプリの動作をローカル環境で再確認します。特にアプリを準備していない場合は、Djangoチュートリアル をもう一度実行してください。すると次のようなファイル構成(一部省略しています)になっているはずです。
1 2 3 4 5 6 7 8 9 10 |
project +-- django ← virtualenvが作ったディレクトリ +-- mysite ← このディレクトリで作業します +-- manage.py +-- mysite +-- __init__.py +-- asgi.py +-- settings.py +-- urls.py +-- wsgi.py |
virtualenv で作った仮想環境 “django” に入ったあとは manage.py がある階層(2つあるmysiteの上位の階層)で作業していきます。チュートリアルがうまく出来ていれば次のコマンドで動作するはずです。
1 |
(django) $ python3 manage.py runserver |
runserver コマンドを実行した状態で http://localhost:8000/polls/ にアクセスして動作を確認してください。もしうまく動作しなかったらチュートリアルの内容を確認してください。
Elastic Beanstalk 用の環境を設定する
引き続き仮想環境 “django” の中で、manage.pyが存在するディレクトリで作業します。次のコマンドでローカル環境で正常に動作している状態の Python のライブラリ一覧を requirements.txt に保存します。Elastic Beanstalk は requirements.txt に記述されたライブラリで動作します。”pip3 freeze” コマンドを実行するタイミングによっては EB CLI を表す “awsebcli==3.xx.x” が紛れ込むかもしれません。この行は必要ありませんので、もし含まれていたら削除してください。
1 |
(django) $ pip3 freeze > requirements.txt |
次に .ebextensions という名前のディレクトリを作成し、その中に django.config という名前のファイルを作ります。.ebextensions/django.config の内容は次のようにします。最後の行の “mysite” は、動作している Django アプリによっては違う名前かもしれませんので自分のアプリのプリジェクト名に合わせてください。
1 2 3 |
option_settings: aws:elasticbeanstalk:container:python: WSGIPath: mysite.wsgi:application |
もう一度ファイル構成を確認してください。下の図は一部省略されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
project +-- django ← virtualenvが作ったディレクトリ +-- mysite ← 作業ディレクトリ +-- .ebextensions | +-- django.config +-- manage.py +-- requirements.txt +-- db.sqlite3 +-- mysite +-- __init__.py +-- asgi.py +-- settings.py +-- urls.py +-- wsgi.py |
EB CLI を使ってデプロイする
EB CLI は AWS Elastic Beanstalk を扱うためのコマンドラインインターフェイスです。このコマンドも virtualenv の環境にインストールしてしまいます。
1 |
(django) $ pip3 install awsebcli --upgrade |
チュートリアルの手順によっては virtualenv が作ったディレクトリ(この例では django ディレクトリ)が manage.py の階層に存在しているかもしれません。その場合は、仮想環境が保存されたディレクトリは Elastic Beanstalk には不要なので、除外するために .ebignore というファイルを作ります。.ebignore の中には1行だけディレクトリ名を書いておきます。GitHub で使用する .gitignore と同じ考え方です。
1 |
django |
manage.py がある階層で eb init コマンドを実行します。色々聞かれますので入力します。過去に eb init コマンドを実行したことがあれば、設定済の項目は表示されないかもしれません。
【重要1】Elastic Beanstalk を使うときは常にリージョンを意識してください。意識せずにデフォルトのまま進めると、どこにデプロイされたかわからなくなってしまいます。例えば「東京(ap-northeast-1)」と決めたら常に「東京」を使うようにしてください。
【重要2】Python は 3.7 を指定してください。3.8 を使うと “Exception Value: deterministic=True requires SQLite 3.8.3 or higher” というエラーが発生します。(このエラーメッセージは DEBUG=Trueで動作させたときに表示されるものです)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
(django) $ eb init Select a default region 1) us-east-1 : US East (N. Virginia) 2) us-west-1 : US West (N. California) 3) us-west-2 : US West (Oregon) 4) eu-west-1 : EU (Ireland) 5) eu-central-1 : EU (Frankfurt) 6) ap-south-1 : Asia Pacific (Mumbai) 7) ap-southeast-1 : Asia Pacific (Singapore) 8) ap-southeast-2 : Asia Pacific (Sydney) 9) ap-northeast-1 : Asia Pacific (Tokyo) 10) ap-northeast-2 : Asia Pacific (Seoul) 11) sa-east-1 : South America (Sao Paulo) 12) cn-north-1 : China (Beijing) 13) cn-northwest-1 : China (Ningxia) 14) us-east-2 : US East (Ohio) 15) ca-central-1 : Canada (Central) 16) eu-west-2 : EU (London) 17) eu-west-3 : EU (Paris) 18) eu-north-1 : EU (Stockholm) 19) eu-south-1 : EU (Milano) 20) ap-east-1 : Asia Pacific (Hong Kong) 21) me-south-1 : Middle East (Bahrain) 22) af-south-1 : Africa (Cape Town) (default is 3): 9 ←リージョンの指定です。「東京」を指定します。 You have not yet set up your credentials or your credentials are incorrect You must provide your credentials. (aws-access-id): XXXXXXXX ←IAMユーザーのAccess key IDです。 (aws-secret-key): XXXXXXXXXXXXXXXX ←IAMユーザーのSecret access keyです。 Enter Application Name (default is "mysite"): django-tutorial ←好きな名前。Elastic Beanstalkのアプリ名になります。 Application django-tutorial has been created. It appears you are using Python. Is this correct? (Y/n): Y ←Pythonであることを確認 Select a platform branch. 1) Python 3.8 running on 64bit Amazon Linux 2 2) Python 3.7 running on 64bit Amazon Linux 2 3) Python 3.6 running on 64bit Amazon Linux (Deprecated) (default is 1): 2 ←Pythonは3.7を指定。 Cannot setup CodeCommit because there is no Source Control setup, continuing with initialization Do you want to set up SSH for your instances? (Y/n): Y ←SSHを使うので"Y" Type a keypair name. (Default is aws-eb): ←このファイルは/Users/ユーザー名/.ssh/aws-ebに保存される Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): ←パスフレーズ無しならEnter Enter same passphrase again: ←もう一度Enter Your identification has been saved in /Users/xx/.ssh/aws-eb Your public key has been saved in /Users/xx/.ssh/aws-eb.pub The key fingerprint is: SHA256:xxxxxxxxxxxxxxxxxxxxxxx aws-eb The key's randomart image is: +---[RSA 3072]----+ | o*++ .| | .E===| +----[SHA256]-----+ WARNING: Uploaded SSH public key for "aws-eb" into EC2 for region ap-northeast-1. (django) $ |
次に “eb create” というコマンドで Django の実行環境を作りますが、ここでロードバランサの種類を意識しなければなりません。AWS のロードバランサにはいくつか種類があり、”eb create” コマンドのオプションで指定できます。デフォルトは Application Load Balancer ですが、筆者は意図せず Classic Load Balancer になってしまった経験があります。明示的に Application Load Balancer を指定するほうが良いでしょう。ロードバランサについては次のページを参考にしてください。
Django用の環境を django-env という名前で作成します。”–elb-type application” は Application Load Balancer を指定するオプションです。コマンドを実行すると、処理の進行状態が表示されます。5分ほどかかるので “Successfully launched environment” と表示されるまで待ってください。
1 2 3 4 5 |
(django) $ eb create --elb-type application django-env (略) 2022-03-15 02:51:09 INFO Successfully launched environment: django-env (django) $ |
正常に終了したら eb status コマンドでドメイン名を確認します。
1 2 3 4 5 6 |
(django) $ eb status Environment details for: django-tutorial (略) CNAME: django-tutorial.eba-xxxxxxxx.com ←この右側がドメイン名 (略) (django) $ |
Django のソースコードにドメイン名を追加します。ファイルは mysite/settings.py です。ALLOWED_HOSTS を次のように変更してください。
1 2 |
#ALLOWED_HOSTS = [] ALLOWED_HOSTS = ['django-tutorial.eba-xxxxxxxx.com'] |
ファイルを保存したらアプリケーションをデプロイします。1分ほどかかるので待ってください。
1 2 3 4 5 |
(django) $ eb deploy (略) 2022-03-16 01:52:40 INFO Environment update completed successfully. (django) $ |
eb open コマンドでWEBページを開いてみます。
1 |
(myprojectenv) $ eb open |
アプリによっては、そもそもURLだけでは動作しない場合もあると思います。Polls アプリだったらURLの後ろに /polls/ とか /admin/ を付けて試してください。ここではまだ静的ファイルが反映されていませんが気にしないでください。
アプリケーションの更新
Django アプリケーションの設定を続けます。まずローカルのデータベースを初期化します。ローカル環境で動作させていれば “No changes” などのメッセージが出ますがそれでOKです。
1 2 |
(django) $ python3 manage.py makemigrations (django) $ python3 manage.py migrate |
サイトの管理者を作成します。すでに作成されていればそのままでも構いません。
1 |
(django) $ python3 manage.py createsuperuser |
mysite/settings.py を何箇所か調整します。公開するサイトではデバッグモードを無効にします。実行時にエラーが発生したときは一時的に DEBUG=True に戻せばエラー内容を確認できることがありますので覚えておいてください。
1 2 |
#DEBUG = True DEBUG = False |
静的ファイルを参照する場所を mysite/settings.py の中で定義します。
1 2 |
STATIC_URL = '/static/' STATIC_ROOT = 'static' |
静的ファイルを集めます。
1 |
(django) $ python3 manage.py collectstatic |
さらに .ebextensions/django.config に数行追加して以下のようにします。このファイルではタブを使わずにスペースを使ってください。タブを使うどエラーになります。
1 2 3 4 5 |
option_settings: aws:elasticbeanstalk:container:python: WSGIPath: mysite.wsgi:application aws:elasticbeanstalk:environment:proxy:staticfiles: /static: static |
加えた変更を反映させるためにデプロイします。
1 |
(django) $ eb deploy |
WEBページを開きます。
1 |
(myprojectenv) $ eb open |
こんどは静的ファイルも反映されます。
実験目的で使用するならここまでの実装で十分な場合も多いはずです。より本格的な運用のために設定を続ける場合には別の記事を参照してください。
デプロイしたアプリケーションの削除
デプロイした環境・アプリケーションは eb terminate コマンドで終了できます。
1 |
(django) $ eb terminate django-env |
eb init コマンドを実行した記録はプロジェクトのディレクトリの .elasticbeanstalk というディレクトリに残っています。このディレクトリを削除すれば初期状態に戻ります。
Elastic Beanstalk はデプロイ時にAWSの様々なインスタンスを作ります。その殆どは eb terminate コマンドで削除されますが、Amazon S3 バケットだけは削除されません。S3バケットを完全に削除してしまいたい場合は次のページの手順に従ってください。