151

投稿日

更新日

【丁寧解説】秒速でもDjango 3アプリをAWS EC2で公開【Nginx, gunicorn, postgresqlデプロイ】

Nginx, gunicorn, postgresqlを最低限の構成でAWS EC2にデプロイ

 WebアプリをPythonで作るなら第一候補がDjangoで、最新の3系デプロイします。。
超最低限のAWSデプロイだけど丁寧に解説するのが今回の記事のテーマです。
図を多めで丁寧に書いたので長く感じますが、慣れれば20分くらいでも終わると思います。

今回使うものは↓で、一つのEC2で全部済ませる構成。シンプル構成なのでデプロイ練習に。
image.png

Djangoのチュートリアルなどですと、herokuの無料版にデプロイすると思いますが、
業務にしても、ポートフォリオ作るにしてもherokuだと望ましくありません。

✖️ 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

手順

  1. Githubにプライベートリポジトリ作る
  2. ローカルで最低限のアプリをDjangoで作る
  3. pushする
  4. EC2作成
  5. AWSでGitからコードを取得してデプロイ
  6. 完成したので壊す

初心者ならこの通りに一度AWSでデプロイの練習してみると良いと思います。これがちゃんとできたら自分のアプリデプロイするとか、自分の過去の記事のような簡単なアプリデプロイしてみてください。

1. Githubにリポジトリ作る

今回の記事はパブリックリポジトリで公開しても大丈夫なように作成はします。

ただし、初心者の方はプライベートリポジトリでやったほうが安全なので、プライベートで作成。
公開すると危ないものをうっかり公開するかもしれないので。

スクリーンショット 2021-01-22 17.05.32.png

このように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

http://127.0.0.1:8000/

ロケットが飛んだらOK

3. .envで公開したらヤバいデータを記述する

manage.pyがあるディレクトリに.envという名前のファイルを作成。

settings.pyに書かれてる下の3つを.envに書く。
※無駄なスペースや', "を入れないこと。

/django-aws/.env
SECRET_KEY=1234567890sdogdmsmoa@:dmmgsv94kmvaso(9l
DEBUG=False
DATABASE_URL=sqlite:///db.sqlite3

該当の項目を.envから読み込むように変更する

settings.py
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記述を確認しましょう。

.gitignore
.env

これで環境変数をgithubのリポジトリには入れないようにできます。

4. 動作に必要なライブラリを本番環境で入れるためにrequirements.txt作る

ローカルで使っているライブラリを書き出します。
後ほど、これを使ってライブラリをデプロイするサーバーにインストールします。

$ pip freeze > requirements-dev.txt

これで、ローカルで動作するのに必要なライブラリをrequirements-dev.txtに書きだせました。

ローカルのライブラリ以外にEC2で追加で使うライブラリを追加

次にrequirements.txtを作成して

/django-aws/requirements.txt
-r requirements-dev.txt
gunicorn
psycopg2

と書くと、開発環境で動作させるのに必要なライブラリが書いてあるrequirements-dev.txtに、追加して
本番環境の構築に必要なライブラリを記述する書き方ができます。

5. 簡単な文字を表示するだけのアプリを作る

ルーティングを追加。

django-aws/testapp/urls.py
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メソッドを使ってページを作ると記述。

django-aws/app/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

文字だけアプリという文字だけのHTMLをレンダリングするだけの処理を書く。

django-aws/app/views.py
from django.http import HttpResponse


def index(request):
    return HttpResponse('文字だけアプリ')

↓アクセスしてみたら

http://127.0.0.1:8000/

スクリーンショット 2021-01-22 19.32.38.png

こんな感じで文字だけ表示するアプリ完成しました(笑)

6. githubにpush

EC2に作成したコードを置ければいいのでgitの他にも方法ありますが、一番楽です。

  1. githubにpushしておく
  2. EC2でgit pullしてコード取得
  3. 今回作ったアプリを動かせるように本番環境作る

では、リポジトリにpushします。
※ すでにこれまでの手順を辿れば設定済みだが念の為、.envはpushしないこと

$ git add .
$ git commit -m "文字だけアプリ"
$ git push

7. AWS EC2にデプロイ作業

アカウントを取るところ、IAMの設定などは省略します。

AWSのコンソールで作業

EC2と検索して選んでください。
※AWSはよくUIが変わるので、もし画像と違ったら、それっぽいもの選ぶようにしてください。

スクリーンショット 2021-01-22 19.41.29.png

で、これを選択
スクリーンショット 2021-01-22 19.43.13.png
「インスタンスを起動」をクリック
スクリーンショット 2021-01-22 19.44.13.png

今回はUbuntu使います。

Ubuntuを選択
スクリーンショット 2021-01-22 19.47.14.png

「無料利用枠」って書いてあるのを選択して下の方にある次のステップ押す
スクリーンショット 2021-01-22 19.49.51.png

変更ないので、次へ
スクリーンショット 2021-01-22 19.51.28.png

4のストレージも変更必要ないので次へ
スクリーンショット 2021-01-22 19.52.47.png

タグの追加も次へ
スクリーンショット 2021-01-22 19.54.06.png

セキュリティグループをわかりやすいように**「django」**に変えて確認と作成を押す。
これは自分が今回使うセキュリティグループ選ぶとき区別つけば良いのでなんでもいいです。

スクリーンショット 2021-01-22 20.01.54.png

セキュリティで脅されてますね。
本来はsshを自分の家、職場のIPだけアクセスできるようにするのが良いのですが、IP変わったりしますし、自宅以外で作業したらアクセスできないとか面倒。
練習ですし、脅しは無視。

スクリーンショット 2021-01-22 20.04.12.png

今回はdjangoappとでも名前つけて、キーペアをダウンロード。自分がわかればいいのでご自由に。
注意:

  1. キーペアは無くさないように。アクセスできなくなります。
  2. このキーは絶対にネットに公開しないこと!
  3. 絶対にgithubでpushするようなディレクトリに入れないこと!
    大変なことになります😇

スクリーンショット 2021-01-22 20.06.06.png

わかりやすいようにホーム直下にaws_keyとでもフォルダ作ってダウンロードしたキーを移動させてください。
そうしたら「インスタンスの作成」を押す。

「インスタンスの表示」を押すと↓の画面に戻れる。
実行中になったら次の手順へ進む

スクリーンショット 2021-01-22 20.11.30.png

接続ボタンを押すか、アクションから接続を押してください。
スクリーンショット 2021-01-25 17.57.34.png

コンソール作業

「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設定

ポスグレ設定していきます。

  1. データベースを作成
  2. ユーザー作成(パスワードは適時変えてください)
  3. DBの文字コードをUTF8にしておく
  4. トランザクション分離レベルを設定。(とりあえずはコピペでOK)
  5. 日本時間に
  6. 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
settings.py
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')

migrateを実行

manage.pyにある階層に移動してmigrateを実行する。

$ python3 manage.py migrate

マイグレートが実行できたらOK!

9. 開発サーバーで確認してみる

Nginx gnicorn使わないならこの章で終わりです。
EC2の画面に戻って、「インバウンドルール」を編集します。

スクリーンショット 2021-01-25 20.00.13.png
インバウンドルールを編集を押す⇨ルールを追加

_2021-01-26_16.40.55.png

いつもローカルで使ってるサーバー起動させれば一応デプロイだけなら完了!

runserverするときにポート8000で起動することにするので、8000を許可しています。

一応完成してるから確認

manage.pyのあるディレクトリにて、ローカルでサーバーするのと同じようにサーバーを起動します。
IPは全部許可だけど、ポートは8000番。
(先ほどインバウンドルールで指定した8000番)

$ python3 manage.py runserver 0.0.0.0:8000

ブラウザにパブリック IPv4 アドレスをコピー。ポートもつけて

54.250.111.11:8000

のようにアクセス。

できた。一応。

スクリーンショット 2021-01-26 16.47.10.png

文字を表示するだけのアプリのデプロイできました。
試作品でも作るレベルならいいかもしれないですが、普通の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で作ったので編集していきます。

インバウンドルールを編集を押す⇨ルールを追加
スクリーンショット 2021-01-25 20.03.07.png

HTTPと、0.0.0.0/0になっているのを確認してルールを保存。

gunicornを再起動して

$ sudo systemctl restart gunicorn

もう一度、パブリックIPをURLに入れると、

http://13.111.111.11/

スクリーンショット 2021-01-29 22.40.16.png

と表示されて、完成!
うまくできましたか?

13. 壊し方

よくある作ってみた記事だと作って終わりですよね。でも、デプロイしたとに

  • 1年の無料期間過ぎたので壊したい
  • 必要なくなった
  • 他のEC2立てたい
  • もう一回練習したい

などあると思います。
ということでサクッと壊していきます。

壊し方

今回必要なのは

  • EC2インスタンスを終了させる
  • セキュリティグループを削除

が必要です。最小限EC2を終了させれば課金されなくなります。

スクリーンショット 2021-01-30 17.07.10.png

「終了」というのが削除です。削除って書いて欲しいですよね😅

そして、左の欄にあるセキュリティグループを選び
スクリーンショット 2021-01-30 17.09.10.png

今回使ったセキュリティグループを選んで削除します。
最初からある「default」は削除しないでください!
スクリーンショット 2021-01-30 17.10.46.png

これで終わりです。

Elastic IP使ってる人は開放

あと、今回は使ってないので飛ばしてOKですが、
Elastic IPを使って、EC2インスタンスを、停止、再起動してもIPアドレスを変えないようにするサービスを使う時がよくあります。

もし使っている場合はEC2を終了させた後に「開放」してください。開放しないと毎月数百円取られます。

左の蘭から

  1. Elastic IP
  2. EC2との紐付け解除
  3. Elastic IP開放
  4. EC2終了
  5. セキュリティグループ削除

でやるといいと思います。

補足cssを効かせる

表示するという目的は果たしました。でも、

http://13.111.111.11/admin/

にすると、管理画面が出るんですが、
スクリーンショット 2021-01-29 22.43.46.png

CSSが効いてません。
Djangoはデプロイする時にはCSSとか画像、JSフィいるなど静的ファイル(static files)を使う時にはコマンドが必要なんです。
manage.pyと同じところにstaticフォルダ作って、settings.pyの一番下に以上の記述追加。

~/django-aws
$ mkdir static
$ cd testapp
$ vim settings.py

cssを保存するディレクトリの設定を追記する。

settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
~/django-aws
$ 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で指定したディレクトリになります。
これで完成したのでアクセスしてみると

http://13.111.111.11/admin/

できました。

スクリーンショット 2021-01-30 2.01.22.png

superuser作成して一応管理画面活用してみる

デフォルトで管理画面作る機能がDjangoにはあるので使ってみましょう。(非常に便利!)
superuser作ってログインします。

$ python3 manage.py createsuperuser
Username (leave blank to use 'ubuntu'): djangosuper
Email address:
Password:
Password (again):
Superuser created successfully.

名前とパスワードをつけて作ってください。(passwordは打っても何も表示されない)
デフォルトではmail入力不要なので入れても入れなくてもいいです。これはもちろん全世界からアクセスできるのでパスワードは複雑なものにしましょう。

完成です!

スクリーンショット 2021-01-30 2.09.33.png

この画面からDBにデータ追加したりアクセス制限かけたりできます。
こういうのを扱ったDjangoアプリの記事は昔作ったので参考にしてください。

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
ログインすると使える機能について
151