Nginx, gunicorn, postgresqlを最低限の構成でAWS EC2にデプロイ
WebアプリをPythonで作るなら第一候補がDjangoで、最新の3系デプロイします。。
超最低限のAWSデプロイだけど丁寧に解説するのが今回の記事のテーマです。
図を多めで丁寧に書いたので長く感じますが、慣れれば20分くらいでも終わると思います。
今回使うものは↓で、一つのEC2で全部済ませる構成。シンプル構成なのでデプロイ練習に。
Djangoのチュートリアルなどですと、herokuの無料版にデプロイすると思いますが、
業務にしても、ポートフォリオ作るにしてもherokuだと望ましくありません。
更新: herokuは有料化しています。無料でデプロイできるサービス(Fly.ioなど)は他にもありますが、現状はAWSでデプロイできる方がスキル的に有利になると思います。
✖️ herokuデプロイのデメリット
- 無料だとアクセスに時間かかる(しばらくアクセスされていない場合)
- herokuデプロイだとポートフォリオに使うには少し手抜き感を持つ採用者増えた
- 日本の企業で使うなら大体AWS
⭕️ herokuデプロイのメリット
- 無料で簡単。初心者に優しい
- 情報も多い
✖️ AWSデプロイのデメリット
- AWSは1年間の無料期間過ぎてしまうと、毎月がアクセスなくても店で「うな重」食えるくらいはお金かかる
- 少し複雑。インフラ周りの知識がいる
⭕️ AWSデプロイのメリット
- 使っていない会社の方が少ないので就職・転職・フリーランスいずれもキャリア有利になるはず
- インフラ周りの知識つく
- 高単価になりやすいDevOpsエンジニアの基礎学べる
ということで、今回はAWSを秒でデプロイすることに特化するけど丁寧に!
を心がけて記事に書きます。
勉強・練習用も兼ねているという人のために、お金かからないように、デプロイしたアプリを解除する方法も書きますのでご安心を。
環境
- Mac
- Python 3.8
- Django 3.1.5
- PostgreSQL 12.5
- Nginx 1.18.0
- gunicorn 20.0.4
手順
- Githubにプライベートリポジトリ作る
- ローカルで最低限のアプリをDjangoで作る
- pushする
- EC2作成
- AWSでGitからコードを取得してデプロイ
- 完成したので壊す
初心者ならこの通りに一度AWSでデプロイの練習してみると良いと思います。これがちゃんとできたら自分のアプリデプロイするとか、自分の過去の記事のような簡単なアプリデプロイしてみてください。
1. Githubにリポジトリ作る
今回の記事はパブリックリポジトリで公開しても大丈夫なように作成はします。
ただし、初心者の方はプライベートリポジトリでやったほうが安全なので、プライベートで作成。
公開すると危ないものをうっかり公開するかもしれないので。
このようにadd .gitignore
にチェック入れてpythonを選ぶと自動的に公開しない方が良いファイルを除外した設定で作成できて便利です。
githubからクローンする
$ mkdir django
$ cd django
Macでsshを設定しておいてください。記事色々ありますので探せば見つかると思いますが、自分の記事も載せておきます。Ubuntuと書いてありますが、Macも同じ方法でできます。
sshを設定済みの人はhttpsでURLをコピーしてクローンしてローカルに取得する。
$ git clone ここにコピーしたURL
$ cd django-aws
※ 私の場合はdjango-aws
でリポジトリ作りました
2. ローカルで最低限のアプリをDjangoで作る
今回はpipenvを使って仮想環境作ります。
私の環境にちょうど入っていただけなのでローカルで作るならなんでもいいです!
一応、以前書いたPipenv環境構築記事貼っておきます。今回使うのMacですが...
-> 私のanaconda重すぎ…?だったのでPipenv使う【Windows10 Python環境構築】
pipenvインストールしてなかったら、入れてバージョンを指定。
$ pip install pipenv
$ pipenv --python 3.8.7
djangoと、.envファイル読むためのもの、DBにアクセスするため必要なもの入れます。
$ pipenv install django
$ pipenv install django-environ
$ pipenv install dj-database-url
仮想環境立ち上げて、testapp
というプロジェクトと、app
というアプリを作ります。
startproject testapp .
ってやるとカレンとディレクトリにプロジェクト作ります。
$ pipenv shell
$ django-admin startproject testapp .
$ django-admin startapp app
manage.pyがあるところで、コマンド打って、ローカルサーバーを起動してみる
$ python manage.py runserver
ロケットが飛んだらOK
3. .envで公開したらヤバいデータを記述する
manage.pyがあるディレクトリに.env
という名前のファイルを作成。
settings.pyに書かれてる下の3つを.envに書く。
※無駄なスペースや'
, "
を入れないこと。
SECRET_KEY=1234567890sdogdmsmoa@:dmmgsv94kmvaso(9l
DEBUG=False
DATABASE_URL=sqlite:///db.sqlite3
該当の項目を.envから読み込むように変更する
import environ
import os
.
.
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
INSTALLED_APPS = [
'app.apps.AppConfig', # 追加
]
.
.
.
DATABASES = {
'default': env.db(),
}
※'app.apps.AppConfig'
はcreateappでapp
と指定したからこのようになっています。djangoapp
でcreateappしたら'djangoapp.apps.DjangoappConfig'
になる。
gitignore確認
手順の通りやれば問題ないと思いますが、違う方法でやった人は以下の.gitignore
の.env
記述を確認しましょう。
.env
これで環境変数をgithubのリポジトリには入れないようにできます。
4. 動作に必要なライブラリを本番環境で入れるためにrequirements.txt作る
ローカルで使っているライブラリを書き出します。
後ほど、これを使ってライブラリをデプロイするサーバーにインストールします。
$ pip freeze > requirements-dev.txt
これで、ローカルで動作するのに必要なライブラリをrequirements-dev.txt
に書きだせました。
ローカルのライブラリ以外にEC2で追加で使うライブラリを追加
次にrequirements.txt
を作成して
-r requirements-dev.txt
gunicorn
psycopg2
と書くと、開発環境で動作させるのに必要なライブラリが書いてあるrequirements-dev.txt
に、追加して
本番環境の構築に必要なライブラリを記述する書き方ができます。
5. 簡単な文字を表示するだけのアプリを作る
ルーティングを追加。
from django.contrib import admin
from django.urls import path, include #追加
urlpatterns = [
path('admin/', admin.site.urls),
path('',include("app.urls")) #追加
]
app
アプリにあるルーティングを読み込むように追加。
urls.pyをappディレクトリのなかに作成
localhost:8000/にアクセスしたらviews.pyのindexメソッドを使ってページを作ると記述。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
文字だけアプリ
という文字だけのHTMLをレンダリングするだけの処理を書く。
from django.http import HttpResponse
def index(request):
return HttpResponse('文字だけアプリ')
↓アクセスしてみたら
こんな感じで文字だけ表示するアプリ完成しました(笑)
6. githubにpush
EC2に作成したコードを置ければいいのでgitの他にも方法ありますが、一番楽です。
- githubにpushしておく
- EC2でgit pullしてコード取得
- 今回作ったアプリを動かせるように本番環境作る
では、リポジトリにpushします。
※ すでにこれまでの手順を辿れば設定済みだが念の為、.env
はpushしないこと
$ git add .
$ git commit -m "文字だけアプリ"
$ git push
7. AWS EC2にデプロイ作業
アカウントを取るところ、IAMの設定などは省略します。
AWSのコンソールで作業
EC2と検索して選んでください。
※AWSはよくUIが変わるので、もし画像と違ったら、それっぽいもの選ぶようにしてください。
今回はUbuntu使います。
「無料利用枠」って書いてあるのを選択して下の方にある次のステップ押す
セキュリティグループをわかりやすいように**「django」**に変えて確認と作成を押す。
これは自分が今回使うセキュリティグループ選ぶとき区別つけば良いのでなんでもいいです。
セキュリティで脅されてますね。
本来はsshを自分の家、職場のIPだけアクセスできるようにするのが良いのですが、IP変わったりしますし、自宅以外で作業したらアクセスできないとか面倒。
練習ですし、脅しは無視。
今回はdjangoappとでも名前つけて、キーペアをダウンロード。自分がわかればいいのでご自由に。
注意:
- キーペアは無くさないように。アクセスできなくなります。
- このキーは絶対にネットに公開しないこと!
- 絶対にgithubでpushするようなディレクトリに入れないこと!
大変なことになります😇
わかりやすいようにホーム直下にaws_key
とでもフォルダ作ってダウンロードしたキーを移動させてください。
そうしたら「インスタンスの作成」を押す。
「インスタンスの表示」を押すと↓の画面に戻れる。
実行中になったら次の手順へ進む
コンソール作業
「SSHクライアント」っていうタブに接続方法書いてありますのでターミナルで接続してみましょう。
自分のPCで、先ほどキーファイルを保存したディレクトリに移動
して
書いてあるコマンドを打ちます。おそらくこんな感じのコマンドが書いてあるはず
$ chmod 400 ここが鍵の名前
$ ssh -i "鍵名" ubuntu@ec2-13-111-111-111.ap-northeast-1.compute.amazonaws.com
2-13-111-111-111の数字が違うと思います。
「例:」のところに書いてあるものそのままコンソールにコピペ。
その後
Are you sure you want to continue connecting (yes/no/[fingerprint])?
って聞かれるのでyes
と入力
これでEC2(OSはUbuntu)の中に入れました。
8. 作ったEC2(Ubuntu)内での作業
EC2って言っても、ただのLinuxのPCってことなのでMacに環境作っていくのとそんなに大差ないと思って進めていきましょう!
Ubuntuのパッケージ管理はapt-getです。古いかもしれないのでアップデートしておきます。
※ Macのbrewみたいなものです。
# cd で一応homeディレクトリで行うことにする
$ cd
$ sudo apt-get update
※ セキュリティ気になる人はユーザーを新規作成して権限などを付与してください。ここでは飛ばします。
今回使うものを一式DLします。
PythonとDBにはポスグレ、サーバーソフトのnginxと、その他必要なライブラリを入れます。
$ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx
[Y/n]出たらY
入力。
DB postgresql設定
ポスグレ設定していきます。
- データベースを作成
- ユーザー作成(パスワードは適時変えてください)
- DBの文字コードをUTF8にしておく
- トランザクション分離レベルを設定。(とりあえずはコピペでOK)
- 日本時間に
- DBの全ての権限を作成したユーザーに付与
$ sudo -u postgres psql
postgres=# CREATE DATABASE djangodb;
postgres=# CREATE USER django WITH PASSWORD 'testPassword1';
postgres=# ALTER ROLE django SET client_encoding TO 'utf8';
postgres=# ALTER ROLE django SET default_transaction_isolation TO 'read committed';
postgres=# ALTER ROLE django SET timezone TO 'UTC+9';
postgres=# GRANT ALL PRIVILEGES ON DATABASE djangodb TO django;
postgres=# \q
ついでにバックスラッシュの打ち方はMacならoption + ¥です。
仮想環境に入れる
こちらではvirtualenvを仮想環境に使います。アップデートとインストールして、
$ sudo -H pip3 install --upgrade pip
$ sudo -H pip3 install virtualenv
では、仮想環境作って入っていきます。
仮想環境の名前はdjangoにしてますが、わかりやすい名前でいいです。
source django/bin/activate
で仮想環境を起動します。
$ virtualenv django
$ source django/bin/activate
うまく仮想環境に入れたら(django)
みたいに先頭に仮想環境の名前が表示されます。
今後、Djangoでmanage.pyとか使うときは仮想環境に入らないと使えないので注意しましょう。
作成したコードをgithubからclone
Githubからcloneします。
2021年の8月ごろにhttpsだとセキュリティの問題でcloneめんどくさくなってるみたいなのでsshでcloneする方法追加しました。
以下の記事参考にcloneしてください
今回はhomeディレクトリにDjangoのプロジェクトをcloneすることにします。
$ cd
$ git clone git@github.com:ユーザー名/リポジトリ名.git
その後、必要なライブラリをローカルで書き出したrequirements.txt
使ってインストールしていきます。
$ ls
django django-aws
$ cd django-aws
$ pip install -r requirements.txt
.envを作る
gitignoreで除外しているのでローカルにはあった.env
ファイルがありません。
作成しないと、Djangoで使うsercret keyとかが読み出せなくてエラー出ますので作成します。
ローカルと同じようにmanage.pyと同じ階層に作成します。
$ vim .env
ローカルにある.envの以下の二つを貼り付け、その下にDBの接続設定。
postgres://USER:PASSWORD@HOST:PORT/NAME
というルールで書くと接続できます。
SECRET_KEY=1234567890sdogdmsmoa@:dmmgsv94kmvaso(9l
DEBUG=False
DATABASE_URL=postgres://django:ここにさっき設定したDBのパスワード@localhost:/djangodb
ALLOWED_HOSTS=13.111.111.111
※ 一応、vimはi
押して編集。esc + : + wq
で保存です。
ALLOWED_HOSTSはAWSのEC2のコンソール画面に書いてあるパブリック IPv4 アドレス
を入力してください。
※1 注意:このHOSTのIP、AWSのElastic IPアドレスっていうのを設定しないと、インスタンスを停止させるたびに変化します。ということで、もしそれを設定前に止めてしまったらここを再設定する必要あります。
※2 Elastic IPアドレスを設定すれば再設定は不要なのですが、紐付けたインスタンスを停止していると、月に数100円かかるかもしれません!もう使わないインスタンスならElastic IPは開放した方がいいです。
settings.pyを編集
.envに記述を追加したので読み込めるようにします。
$ cd testapp
$ vim settings.py
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
migrateを実行
manage.pyにある階層に移動してmigrateを実行する。
$ python3 manage.py migrate
マイグレートが実行できたらOK!
9. 開発サーバーで確認してみる
Nginx gnicorn使わないならこの章で終わりです。
EC2の画面に戻って、「インバウンドルール」を編集します。
いつもローカルで使ってるサーバー起動させれば一応デプロイだけなら完了!
runserverするときにポート8000で起動することにするので、8000を許可しています。
一応完成してるから確認
manage.pyのあるディレクトリにて、ローカルでサーバーするのと同じようにサーバーを起動します。
IPは全部許可だけど、ポートは8000番。
(先ほどインバウンドルールで指定した8000番)
$ python3 manage.py runserver 0.0.0.0:8000
ブラウザにパブリック IPv4 アドレスをコピー。ポートもつけて
54.250.111.11:8000
のようにアクセス。
できた。一応。
文字を表示するだけのアプリのデプロイできました。
試作品でも作るレベルならいいかもしれないですが、普通のDjangoの構成ならgunicorn nginx
を使いますので使えるようにしていきましょう。
10. gunicornの設定
一旦仮想環境から抜けて作業していきます。
$ deactivate
gunicornの設定を書いていきます。
$ sudo vim /etc/systemd/system/gunicorn.service
わたしの場合は、以下のようになります。
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/django-aws
ExecStart=/home/ubuntu/django/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/django-aws/testapp.sock testapp.wsgi:application
[Install]
WantedBy=multi-user.target
WorkingDirectory=/home/ubuntu/リポジトリの名前と同じ
ExecStart=/home/ubuntu/仮想環境の名前/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/リポジトリの名前と同じ/Djangoのプロジェクト名.sock Djangoのプロジェクト名.wsgi:application
だけ調整してください。
Gunicorn serviceの自動起動と有効化
$ sudo systemctl start gunicorn.service
$ sudo systemctl enable gunicorn
11. nginxの設定
次はnginxの設定ファイルを作成します。
sudo vim /etc/nginx/sites-available/リポジトリの名前と同じ
$ sudo vim /etc/nginx/sites-available/django-aws
以下を修正してください。
server {
listen 80;
server_name ここにパブリックIP;
location = /favicon.ico {access_log off; log_not_found off;}
location /static/ {
root /home/ubuntu/リポジトリの名前と同じ;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/リポジトリの名前と同じ/プロジェクト名.sock;
}
}
シンボリックリンクを作成
$ sudo ln -s /etc/nginx/sites-available/django-aws /etc/nginx/sites-enabled/
niginx起動して80番ポートを開放。
先ほど、python manage.py runserver
をした人は8000番を一応削除してます。
$ sudo systemctl restart nginx
$ sudo ufw delete allow 8000
$ sudo ufw allow 'Nginx Full'
12. セキュリティグループ設定
先ほど、8000番ポートを通したものを変更。HTTP
に変更します。
※ 8000番はもう使わないので消した方がいいです。
セキュリティグループを今回の場合はdjango
で作ったので編集していきます。
HTTPと、0.0.0.0/0になっているのを確認してルールを保存。
gunicornを再起動して
$ sudo systemctl restart gunicorn
もう一度、パブリックIPをURLに入れると、
と表示されて、完成!
うまくできましたか?
13. 壊し方
よくある作ってみた記事だと作って終わりですよね。でも、デプロイしたとに
- 1年の無料期間過ぎたので壊したい
- 必要なくなった
- 他のEC2立てたい
- もう一回練習したい
などあると思います。
ということでサクッと壊していきます。
壊し方
今回必要なのは
- EC2インスタンスを終了させる
- セキュリティグループを削除
が必要です。最小限EC2を終了させれば課金されなくなります。
「終了」というのが削除です。削除って書いて欲しいですよね😅
今回使ったセキュリティグループを選んで削除します。
最初からある「default」は削除しないでください!
これで終わりです。
Elastic IP使ってる人は開放
あと、今回は使ってないので飛ばしてOKですが、
Elastic IP
を使って、EC2インスタンスを、停止、再起動してもIPアドレスを変えないようにするサービスを使う時がよくあります。
もし使っている場合はEC2を終了させた後に「開放」してください。開放しないと毎月数百円取られます。
左の蘭から
- Elastic IP
- EC2との紐付け解除
- Elastic IP開放
- EC2終了
- セキュリティグループ削除
でやるといいと思います。
補足cssを効かせる
表示するという目的は果たしました。でも、
CSSが効いてません。
Djangoはデプロイする時にはCSSとか画像、JSフィいるなど静的ファイル(static files)を使う時にはコマンドが必要なんです。
manage.pyと同じところにstaticフォルダ作って、settings.pyの一番下に以上の記述追加。
$ mkdir static
$ cd testapp
$ vim settings.py
cssを保存するディレクトリの設定を追記する。
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
$ source ~/django/bin/activate
$ python3 manage.py collectstatic
132 static files copied to '/home/ubuntu/django-aws/static'.
静的ファイルを/home/ubuntu/django-aws/static
に集めたよーと言っていますね。
このディレクトリはさっきsettings.py
で指定したディレクトリになります。
これで完成したのでアクセスしてみると
できました。
superuser作成して一応管理画面活用してみる
デフォルトで管理画面作る機能がDjangoにはあるので使ってみましょう。(非常に便利!)
superuser作ってログインします。
$ python3 manage.py createsuperuser
Username (leave blank to use 'ubuntu'): djangosuper
Email address:
Password:
Password (again):
Superuser created successfully.
名前とパスワードをつけて作ってください。(passwordは打っても何も表示されない)
デフォルトではmail入力不要なので入れても入れなくてもいいです。これはもちろん全世界からアクセスできるのでパスワードは複雑なものにしましょう。
完成です!
この画面からDBにデータ追加したりアクセス制限かけたりできます。
こういうのを扱ったDjangoアプリの記事は昔作ったので参考にしてください。