以下は、正気を保ちながらDjangoアプリケーションをセットアップしてアマゾンウェブサービス(AWS)にデプロイする方法の概要です。
使用したツール/テクノロジー:
- Python v2.7.8
- Django v1.7
- Amazon Elastic Beanstalk、EC2、S3、およびRDS
- EB CLI 3.x
- PostgreSQL
Python 3が登場しました! この記事の更新版をここでチェックしてください。
AWSはPython3を非常に愛しているため、この記事はPython3でのデプロイをカバーするように更新されました。
Elastic Beanstalk vs EC2
Elastic Beanstalkは、Amazon AWSでのアプリのセットアップ、デプロイ、メンテナンスを合理化するPlatform As A Service(PaaS)です。これはマネージドサービスであり、サーバー(EC2)、データベース(RDS)、および静的ファイル(S3)を結合します。アプリケーションをすばやくデプロイして管理できます。アプリケーションは、サイトの成長に合わせて自動的に拡張されます。詳細については、公式ドキュメントを確認してください。
はじめに
このリポジトリから取得できるシンプルな「ImageoftheDay」アプリを使用します:
$ git clone https://github.com/realpython/image-of-the-day.git
$ cd image-of-the-day/
$ git checkout tags/start_here
コードをダウンロードしたら、virtualenvを作成し、pipを介して要件をインストールします。
$ pip install -r requirements.txt
次に、PostgreSQLをローカルで実行して、iotd
という名前の新しいデータベースをセットアップします。 。また、ローカルのPostgres構成によっては、DATABASES
を更新する必要がある場合があります。 settings.pyでの構成 。
たとえば、構成を次のように更新しました:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'iotd',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}
}
これで、データベーススキーマを設定し、スーパーユーザーを作成して、アプリを実行できます。
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
ブラウザの管理ページ(http:// localhost:8000 / admin)に移動し、新しい画像を追加すると、メインページに表示されます。
このアプリケーションは、非常にエキサイティングなものではありません。デモ目的で使用しているだけです。管理インターフェースを介して画像をアップロードし、その画像をメインページに全画面表示するだけです。とはいえ、これは比較的基本的なアプリですが、AmazonBeanstalkとRDSにデプロイするときに存在する多くの「落とし穴」を調査することもできます。
ローカルマシンでサイトが稼働しているので、Amazonのデプロイプロセスを開始しましょう。
AWSElasticBeanstalkのCLI
Amazon Elastic Beanstalkを使用するには、awsebcliというパッケージを使用できます。これを書いている時点で、の最新バージョンは3.0.10であり、それをインストールするための推奨される方法はpipを使用することです:
$ pip install awsebcli
このパッケージのインストールにbrewを使用しないでください。この記事の執筆時点では、v2.6.3がインストールされていますが、これは微妙な方法で壊れており、深刻なフラストレーションにつながります。
次に、インストールをテストして、機能していることを確認します。
$ eb --version
これにより、3.xのバージョン番号がわかります:
EB CLI 3.0.10 (Python 2.7.8)
Elastic Beanstalkの使用を実際に開始するには、AWSのアカウントが必要です(サプライズ!)。サインアップ(またはログイン)。
EBの構成–アプリの初期化
AWS Elastic Beanstalk CLIが機能している状態で、最初に実行したいのは、アプリケーションをホストするBeanstalk環境を作成することです。これをプロジェクトディレクトリ(「今日の画像」)から実行します:
$ eb init
これにより、環境の構成に役立ついくつかの質問が表示されます。
デフォルトのリージョン
エンドユーザーに最も近い地域を選択すると、通常、最高のパフォーマンスが得られます。どちらを選択すればよいかわからない場合は、この地図を確認してください。
資格情報
次に、AWSのクレデンシャルを要求します。
ここでは、IAMユーザーを設定することをお勧めします。設定方法については、このガイドを参照してください。新しいユーザーを設定する場合は、そのユーザーに適切な権限があることを確認する必要があります。これを行う最も簡単な方法は、ユーザーに「管理者アクセス」を追加することです。 (ただし、セキュリティ上の理由から、これはおそらく適切な選択ではありません。)Elastic Beanstalkアプリケーションを作成/管理するためにユーザーが必要とする特定のポリシー/役割については、こちらのリンクを参照してください。
アプリケーション名
これはデフォルトでディレクトリ名になります。それに合わせてください。
Pythonバージョン
次に、CLIは、Pythonを使用していることを自動的に検出し、確認を求める必要があります。イエスと言う。次に、プラットフォームのバージョンを選択する必要があります。 Python 2.7
を選択します 。
SSH
インスタンスのSSHの設定に「はい」と答えます。
RSAキーペア
次に、RSAキーペアを生成する必要があります。これは〜/ .sshに追加されます。 フォルダ。このキーペアは、ステップ1で指定したリージョンのEC2公開キーにもアップロードされます。これにより、このチュートリアルの後半でEC2インスタンスにSSHで接続できるようになります。
何を達成しましたか?
一度eb init
終了すると、 .elasticbeanstalkという新しい隠しフォルダが表示されます。 プロジェクトディレクトリ内:
├── .elasticbeanstalk
│ └── config.yml
├── .gitignore
├── README.md
├── iotd
│ ├── images
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── iotd
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ ├── static
│ │ ├── css
│ │ │ └── bootstrap.min.css
│ │ └── js
│ │ ├── bootstrap.min.js
│ │ └── jquery-1.11.0.min.js
│ └── templates
│ ├── base.html
│ └── images
│ └── home.html
├── requirements.txt
└── www
└── media
└── sitelogo.png
そのディレクトリ内にはconfig.yml
があります fileは、新しく作成されたBeanstalkアプリケーションの特定のパラメーターを定義するために使用される構成ファイルです。
この時点で、eb console
と入力すると デフォルトのブラウザが開き、ElasticBeanstalkコンソールに移動します。このページには、1つのアプリケーション(image-of-the-day
と呼ばれる)が表示されます。 正確にフォローしている場合)が、環境はありません。
アプリケーションはコードアプリケーションを表し、eb init
私たちのために作成されました。 Elastic Beanstalkを使用すると、アプリケーションは複数の環境(つまり、開発、テスト、ステージング、本番)を持つことができます。これらの環境をどのように構成/管理するかは完全にあなた次第です。単純なDjangoアプリケーションの場合、ラップトップに開発環境を置き、Beanstalkでテスト環境と本番環境を作成するのが好きです。
テスト環境をセットアップしましょう…
EBの構成–環境の作成
ターミナルに戻って、プロジェクトディレクトリに次のように入力します。
$ eb create
eb init
と同じように 、このコマンドは一連の質問を表示します。
環境名
特にAWSで複数のアプリケーションのホスティングを開始する場合は、Amazonが提案するものと同様の命名規則(たとえば、application_name-env_name)を使用する必要があります。私が使用した-iod-test
。
DNSCNAMEプレフィックス
アプリをElasticBeanstalkにデプロイすると、xxx.elasticbeanstalk.comのようなドメイン名が自動的に取得されます。 DNS CNAME prefix
xxx
の代わりに使用したいものです 。デフォルトのままにします。
今何が起こっているのですか?
この時点でeb
実際にあなたのためにあなたの環境を作成します。しばらく時間がかかる場合がありますので、しばらくお待ちください。
次のような環境の作成中にエラーが発生した場合-
aws.auth.client.error.ARCInstanceIdentityProfileNotFoundException
-この投稿で前述したように、使用している資格情報にBeanstalk環境を作成するための適切な権限があることを確認してください。
環境が作成された直後に、eb
pip install -r requirements.txt
を実行して、プロジェクトディレクトリ内のすべてのコードを新しいEC2インスタンスにコピーすることにより、アプリケーションのデプロイを試みます。 その過程で。
設定されている環境に関する一連の情報と、eb
に関する情報が画面に表示されます。 展開しようとしています。また、いくつかのエラーが表示されます。特に、これらの行が出力のどこかに埋め込まれているのがわかります。
ERROR: Your requirements.txt is invalid. Snapshot your logs for details.
心配しないでください-それは本当に無効ではありません。詳細についてはログを確認してください:
$ eb logs
これにより、EC2インスタンスから最近のすべてのログファイルが取得され、ターミナルに出力されます。これは多くの情報であるため、出力をファイルにリダイレクトすることをお勧めします(eb logs -z
)。ログを確認すると、 eb-activity.logという名前の1つのログファイルが表示されます。 :
Error: pg_config executable not found.
問題は、psycopy2
をインストールしようとしたことです (Postgres Pythonバインディング)が、Postgresクライアントドライバーもインストールする必要があります。デフォルトではインストールされないため、最初にインストールする必要があります。それを修正しましょう…
展開プロセスのカスタマイズ
eb
カスタムの.config
を読み取ります プロジェクトのルートレベルにある「.ebextensions」というフォルダ(「image-of-the-day」ディレクトリ)のファイル。これらの.config
ファイルを使用すると、パッケージをインストールしたり、任意のコマンドを実行したり、環境変数を設定したりできます。 「.ebextensions」ディレクトリ内のファイルは、JSON
のいずれかに準拠している必要があります またはYAML
構文であり、アルファベット順に実行されます。
パッケージのインストール
最初に行う必要があるのは、pip install
になるようにいくつかのパッケージをインストールすることです。 コマンドは正常に完了します。これを行うには、最初に .ebextensions / 01_packages.configというファイルを作成しましょう。 :
packages:
yum:
git: []
postgresql93-devel: []
EC2インスタンスはRedhatフレーバーであるAmazonLinuxを実行するため、yumを使用して必要なパッケージをインストールできます。今のところ、gitとPostgresクライアントの2つのパッケージをインストールします。
そのファイルを作成してアプリケーションを再デプロイした後、次のことを行う必要があります。
$ git add .ebextensions/
$ git commit -m "added eb package configuration"
デプロイメントコマンドeb deploy
のため、変更をコミットする必要があります 最新のコミットで動作するため、ファイルの変更はgitにコミットした後でのみ認識されます。 (プッシュする必要はありませんが、ローカルコピーから作業していることに注意してください…)
ご想像のとおり、次のコマンドは次のとおりです。
$ eb deploy
エラーが1つだけ表示されるはずです:
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
ERROR: Your WSGIPath refers to a file that does not exist.
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
何が起こっているのか調べてみましょう…
Python環境の構成
BeanstalkのEC2インスタンスはApacheを実行し、Apacheは設定したWSGIPATHに従ってPythonアプリを検出します。デフォルトではeb
wsgiファイルの名前がapplication.pyであると想定しています。 。これを修正する方法は2つあります-
オプション1:環境固有の構成設定を使用する
$ eb config
このコマンドはデフォルトのエディターを開き、 .elasticbeanstalk / iod-test.env.ymlという構成ファイルを編集します。 。このファイルは実際にはローカルに存在しません。 eb
AWSサーバーからプルダウンして表示し、設定を変更できるようにしました。この疑似ファイルに変更を加えてから保存して終了する場合は、eb
Beanstalk環境の対応する設定を更新します。
ファイル内で「WSGI」という用語を検索すると、次のような構成セクションが見つかります。
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: application.py
WSGIPathを更新します:
aws:elasticbeanstalk:container:python:
NumProcesses: '1'
NumThreads: '15'
StaticFiles: /static/=static/
WSGIPath: iotd/iotd/wsgi.py
次に、WSGIPathを正しく設定します。その後、ファイルを保存して終了する場合は、eb
環境構成を自動的に更新します:
Printing Status:
INFO: Environment update is starting.
INFO: Updating environment iod-test's configuration settings.
INFO: Successfully deployed new configuration to environment.
INFO: Environment update completed successfully.
eb config
を使用する利点 設定を変更する方法は、環境ごとに異なる設定を指定できることです。ただし、同じ.config
を使用して設定を更新することもできます 以前使用していたファイル。これは、.config
と同じように、環境ごとに同じ設定を使用します ファイルはデプロイ時に適用されます(eb config
からの設定後) 適用されました。
オプション2:グローバル構成設定の使用
.config
を使用するには ファイルオプション、/。ebextensions/ 02_python.configという名前の新しいファイルを作成しましょう :
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "iotd.settings"
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
"aws:elasticbeanstalk:container:python":
WSGIPath: iotd/iotd/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "www/static/"
何が起こっているのですか?
-
DJANGO_SETTINGS_MODULE: "iotd.settings"
-設定モジュールへのパスを追加します。 -
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
-PYTHONPATH
を更新します そのため、Pythonはアプリケーション内のモジュールを見つけることができます。 (フルパスを使用する必要があることに注意してください。) -
WSGIPath: iotd/iotd/wsgi.py
WSGIパスを設定します。 -
NumProcesses: 3
およびNumThreads: 20
-WSGIアプリケーションの実行に使用されるプロセスとスレッドの数を更新します。 -
"/static/": "www/static/"
静的ファイルのパスを設定します。
ここでも、git commit
を実行できます 次に、eb deploy
これらの設定を更新します。
次に、データベースを追加しましょう。
データベースの構成
デプロイされたWebサイトを表示してみてください:
$ eb open
このコマンドは、デフォルトのブラウザにデプロイされたアプリケーションを表示します。接続拒否エラーが表示されるはずです:
OperationalError at /
could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
これは、データベースをまだ設定していないためです。この時点でeb
Beanstalk環境をセットアップしますが、RDS(データベース層)はセットアップしません。手動で設定する必要があります。
データベースのセットアップ
ここでも、eb console
を使用します Beanstalk構成ページを開きます。
そこから、次の手順を実行します。
- [構成]リンクをクリックします。
- ページの一番下までスクロールし、[データ層]セクションで[新しいRDSデータベースを作成する]リンクをクリックします。
- RDSセットアップページで、「DBエンジン」を「postgres」に変更します。
- 「マスターユーザー名」と「マスターパスワード」を追加します。
- 変更を保存します。
BeanstalkがRDSを作成します。次に、DjangoアプリをRDSに接続する必要があります。 Beanstalkは、Postgresサーバーへの接続方法を詳しく説明しているEC2インスタンス上のいくつかの環境変数を公開することで、ここで私たちを助けてくれます。したがって、必要なのは settings.pyを更新することだけです。 これらの環境変数を利用するためのファイル。 DATABASES
を確認します 構成パラメーターは、 settings.pyの以下を反映します :
if 'RDS_DB_NAME' in os.environ:
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'],
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'iotd',
'USER': 'iotd',
'PASSWORD': 'iotd',
'HOST': 'localhost',
'PORT': '5432',
}
}
これは、「存在する場合は環境変数設定を使用し、存在しない場合はデフォルトの開発設定を使用する」と単純に言います。シンプル。
データベース移行の処理
データベースのセットアップでは、データベーステーブルの構造が正しくなるように、移行が実行されていることを確認する必要があります。これを行うには、 .ebextensions / 02_python.configを変更します。 ファイルの先頭に次の行を追加します。
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py migrate --noinput"
leader_only: true
container_commands
アプリケーションがEC2インスタンスにデプロイされた後、任意のコマンドを実行できるようにします。 EC2インスタンスは仮想環境を使用してセットアップされているため、migrateコマンドを実行する前に、まずその仮想環境をアクティブ化する必要があります。また、leader_only: true
設定とは、「複数のインスタンスにデプロイする場合は、最初のインスタンスでのみこのコマンドを実行する」ことを意味します。
アプリケーションがDjangoの管理者を利用していることを忘れないでください。そのため、スーパーユーザーが必要になります…
管理者ユーザーを作成する
残念ながら、createsuperuser
--noinput
を使用する場合、パスワードを指定することはできません オプションなので、独自のコマンドを作成する必要があります。幸い、Djangoを使用すると、カスタムコマンドを非常に簡単に作成できます。
ファイルiotd/ images / management / commands / createsu.pyを作成します :
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
class Command(BaseCommand):
def handle(self, *args, **options):
if not User.objects.filter(username="admin").exists():
User.objects.create_superuser("admin", "[email protected]", "admin")
適切な__init__.py
を追加してください ファイルも:
└─ management
├── __init__.py
└── commands
├── __init__.py
└── createsu.py
このファイルを使用すると、python manage.py createsu
を実行できます。 、パスワードの入力を求めずにスーパーユーザーを作成します。コマンドを拡張して、環境変数またはパスワードを変更できる別の手段を使用してください。
コマンドを作成したら、container_commands
に別のコマンドを追加するだけです。 .ebextensions / 02_python.configのセクション :
02_createsu:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py createsu"
leader_only: true
これをテストする前に、静的ファイルがすべて正しい場所に配置されていることを確認しましょう…
静的ファイル
container_commands
の下にもう1つのコマンドを追加します :
03_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py collectstatic --noinput"
したがって、ファイル全体は次のようになります。
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py migrate --noinput"
leader_only: true
02_createsu:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py createsu"
leader_only: true
03_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py collectstatic --noinput"
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "iotd.settings"
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
"ALLOWED_HOSTS": ".elasticbeanstalk.com"
"aws:elasticbeanstalk:container:python":
WSGIPath: iotd/iotd/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "www/static/"
ここで、STATIC_ROOT
を確認する必要があります settings.pyで正しく設定されている ファイル:
STATIC_ROOT = os.path.join(BASE_DIR, "..", "www", "static")
STATIC_URL = '/static/'
必ずwww
をコミットしてください 静的ディレクトリを作成できるようにgitするディレクトリ。次に、eb deploy
を実行します 繰り返しますが、これでビジネスを開始できます:
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.
この時点で、http:// your_app_url / adminにアクセスしてログインし、画像を追加して、その画像がアプリケーションのメインページに表示されることを確認できるはずです。
成功!
メディアストレージにS3を使用する
この設定では、再度デプロイするたびに、アップロードされたすべてのイメージが失われます。なんで?さて、eb deploy
を実行すると 、新しいインスタンスがスピンアップされます。これは、データベースに画像のエントリがありますが、関連する画像がないため、必要なものではありません。解決策は、メディアファイルをEC2インスタンス自体ではなく、Amazon Simple Storage Service(Amazon S3)に保存することです。
次のことを行う必要があります:
- バケットを作成する
- ユーザーのARN(Amazonリソース名)を取得する
- バケット権限を追加する
- S3を使用して静的ファイルを提供するようにDjangoアプリを構成します
これについてはすでに良い記事があるので、私のお気に入りを紹介します。AmazonS3を使用してDjangoの静的ファイルとメディアファイルを保存する
Apache Config
BeanstalkでApacheを使用しているので、おそらく、クライアントがファイルをより速くダウンロードできるように、(とりわけ)gzip圧縮を有効にするようにApacheを設定する必要があります。これはcontainer_commands
で実行できます 。新しいファイルを作成します.ebextensions/ 03_apache.config そして、以下を追加します:
container_commands:
01_setup_apache:
command: "cp .ebextensions/enable_mod_deflate.conf /etc/httpd/conf.d/enable_mod_deflate.conf"
次に、ファイル.ebextensions/enable_mod_deflate.conf
を作成する必要があります :
# mod_deflate configuration
<IfModule mod_deflate.c>
# Restrict compression to these MIME types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xml+rss
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css
# Level of compression (Highest 9 - Lowest 1)
DeflateCompressionLevel 9
# Netscape 4.x has some problems.
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
<IfModule mod_headers.c>
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</IfModule>
</IfModule>
これを行うと、gzip圧縮が有効になり、ダウンロードするファイルのサイズに役立ちます。同じ戦略を使用して、CSS / JSを自動的に縮小して結合し、必要なその他の前処理を行うこともできます。
トラブルシューティング
非常に役立つeb ssh
を忘れないでください コマンドを実行すると、EC2インスタンスが表示されるので、何が起こっているのかを確認できます。トラブルシューティングを行うときは、次の点に注意する必要があります。
-
/opt/python
-アプリケーションが終了する場所のルート。 -
/opt/python/current/app
-環境でホストされている現在のアプリケーション。 -
/opt/python/on-deck/app
-アプリは最初にオンデッキに配置され、すべてのデプロイが完了すると、current
に移動されます 。container_commands
でエラーが発生した場合 、on-deck
をチェックしてくださいcurrent
ではなくフォルダ フォルダ。 -
/opt/python/current/env
-eb
のすべての環境変数 あなたのためにセットアップします。エラーを再現しようとしている場合は、最初にsource /opt/python/current/env
が必要になる場合があります。 ebdeployの実行時と同じように設定します。 -
opt/python/run/venv
-アプリケーションで使用される仮想環境。また、source /opt/python/run/venv/bin/activate
を実行する必要があります エラーを再現しようとしている場合
結論
Elastic Beanstalkにデプロイするのは最初は少し難しいかもしれませんが、すべてのパーツがどこにあり、どのように機能するかを理解すれば、実際には非常に簡単で非常に柔軟です。また、使用量の増加に応じて自動的に拡張される環境も提供します。うまくいけば、今までにあなたは危険になるのに十分です!次のBeanstalkの展開に頑張ってください。
私たちは何かを逃しましたか?他にヒントやコツはありますか?以下にコメントしてください。