Edited at

Djangoの既存プロジェクトをec2にデプロイ

More than 1 year has passed since last update.


概要

詰まりまくったのでメモ。Dockerで開発していたのでそのままデプロイしたろ!と思っていたが意味わからなすぎて断念。(おそらく?)一般的な方法でデプロイした。もっと良い方法があれば教えて欲しい限りです。


環境

OS: Amazon Linux AMI release 2017.09

ローカル: Docker

Python: 3.6.2

Django: 1.11.5

Gunicorn: 19.7.1

Nginx: 1.12.1


AWSの設定


インスタンスの作成

AWSの設定はAmazon Web Services 基礎からのネットワーク&サーバー構築を参考にした。

AWSに登録してコンソール > EC2からインスタンスを作成する。全部デフォルト。t2microなら無料。

VPC、サブネット、ルートテーブル、ゲートウェイ、セキュリティグループやらが作成される(はず)。なかったら作ってVPCに紐付ける。sshキーをダウンロードまたは登録しておく。


ポートの開放

EC2 > セキュリティグループからポートが開放できる。セキュリティグループを選択 -> インバウンド -> 編集 -> ルールの追加で80番ポート、8000番ポート(確認用、あとで閉じる)を開く。タイプはカスタムTCP、ソースは0.0.0.0/0で良い。

ここで EC2 > インスタンス から作ったインスタンスの詳細が確認できる。右側のパブリックDNSでドメイン、IPv4パブリックIPでIPが確認できる。


nginxのインストール

AWSにsshでログイン。キーペアをダウンロードした場合は~/.sshに置いて別のキー名を指定する。

# ssh -i ~/.ssh/id_rsa ec2-user@(インスタンスのIP)

以下ではrootで作業する。

$ sudo su -

以下、EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを参考にnginxをインストール。

nginx入れる。

$ yum install nginx

nginxを起動する。

$ nginx

nginxの自動起動設定

$ chkconfig --add nginx

$ chkconfig nginx on

自動起動設定できているか確認する。

$ chkconfig | grep nginx

nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off

また、http://(パブリックDNS)を確認してnginxが起動しているか確認する。


Djangoプロジェクトの起動


AWSにプロジェクトを送る。

scpでzipで固めたDjangoプロジェクトを送る。また送る前にrequirements.txtは用意しておく。

# pip freeze > requirements.txt

# scp -i ~/.ssh/id_rsa ~/path/to/project.zip ec2-user@yourIP:home/ec2-user/

送ったものがhome/ec2-userに落ちているはず。解凍する

$ unzip project.zip

ほんとはgitで落とせばいいんだろうけどプライベートリポジトリにしてるので新しいuser登録して新しくssh登録してってしないといけないのかな。誰か教えてください。


pythonとかを入れる

色々考えるのがめんどくさかったのでEC2サーバにPython3環境構築を参考にした。

gitとpyenv入れる。-yが全部yesって答えるオプションらしい。初めて知った。

$ yum install git -y

$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv

path通す。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile

$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

コマンド通るか確認。

$ pyenv -v

依存関係を入れる。

$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y

本体を入れる。

$ pyenv install 3.6.2

pythonを切り替える。これはrootのpythonなので、sudo su -後でないとデフォルトのpythonに戻ってしまうので注意。

$ pyenv global 3.6.2

$ pyenv rehash
$ python --version
Python 3.6.2

Django、その他諸々のプロジェクトに必要なライブラリをインストールする。

$ pip install --upgrade -r project/requirements.txt

requirements.txtにGunicornが入ってなければGunicornを入れる。

Gunicornとはwsgiサーバーのことで、nginxとDjangoを繋ぐものみたいなイメージ。

$ pip install gunicorn

manage.pyの上でDjangoを起動させる。

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000

http://(パブリックDNS):8000を確認すると、ALLOWED_HOSTSに追加してね!と出るので追加する。


/your_project/settings.py

# 中略

ALLOWED_HOSTS = ['(パブリックDNS)']
# 以下略

もう一回確認してプロジェクトが見えれば成功。


Nginxの設定の変更

再びEC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを丸パクリ。本当にありがとうございました

/etc/nginx.confとあるが、Amazon Linuxでは/etc/nginx/nginx.confにあった。

以下引用


/etc/nginx.confを以下の通り編集する


/etc/nginx.conf

〜中略〜

http {
〜中略〜

upstream app_server {
server 127.0.0.1:8000 fail_timeout=0;
}

server {
#以下4行はコメントアウト
#listen 80 default_server;
#listen [::]:80 default_server;
#server_name localhost;
#root /usr/share/nginx/html;

# 以下3行を追加
listen 80;
server_name IPアドレス or ドメイン;
client_max_body_size 4G;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
# 以下4行を追加
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}

〜以下略〜



nginxの再起動

$ service nginx restart

Stopping nginx: [ OK ]
Starting nginx: [ OK ]

Djangoを再びGunicornで立ち上げる

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000

http://(パブリックDNS)で確認できたら成功。


daemon化

今はコマンドからGunicornを起動しているだけなので、ログアウトしたら終了してしまう。そこでGunicornをデーモン化して常駐するようにしたい。

ただ色々な所を見ると、Surpervisorというツールでそれが可能なようだが、SurpervisorはPython3系に対応していないので2系の環境をもう一つ作れとのこと。んなアホな。

もうちょっと調べてみると、普通に-Dというオプションをつけるだけでデーモンとして起動できるらしい。


起動

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D

終了するときは

$ ps -ef | grep gunicorn

root 17419 1 0 Oct07 ? 00:00:08 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root 17422 17419 0 Oct07 ? 00:00:01 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root 21686 21594 0 08:05 pts/0 00:00:00 grep --color=auto gunicorn
$ kill 17419


スクリプトで起動

ただこのままだと毎回めんどくさいので、シェルスクリプトでサーバーを起動、停止するにあるスクリプトを使わせてもらう。


Flaskとかで作ったちょっとしたサーバーの起動/停止用のシェルスクリプト。

gunicornでデーモン状態にしている。

startで起動、stopで終了、restartでstop+start。


your_project.sh

#!/bin/sh

PROGNAME=`basename $0`
BASEDIR=`dirname $0`
PIDFILE=$BASEDIR/$PROGNAME.pid

start() {
echo "Starting server..."
cd $BASEDIR
gunicorn flaskhello:app -p $PIDFILE -D
}

stop() {
echo "Stopping server..."
kill -TERM `cat $PIDFILE`
rm -f $PIDFILE
}

usage() {
echo "usage: $PROGNAME start|stop|restart"
}

if [ $# -lt 1 ]; then
usage
exit 255
fi

case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
esac



以下のgunicorn flaskhello:app -p $PIDFILE -D

gunicorn your_project.wsgi --bind=0.0.0.0:8000 -Dに書き換える。

$ sh your_project.sh start   #起動

$ sh your_project.sh stop #終了
$ sh your_project.sh restart #再起動

sshを切ってもhttp://(パブリックDNS)が見えたら成功。ひとまず見えるようになった。


staticファイルが見つからない

ただここまで追ってもcss,jsなどstaticファイルは見つかってないはず。以下で見えるようにする。

setting.pyのSTATIC_URL、STATIC_PATHは設定済みでローカルでは見える状態とする。

詳しい解説 -> Django での static files の扱い方まとめ


staticファイルのコピー

manage.pyの上でstaticファイルを指定したディレクトリにコピー

$ python manage.py collectstatic


nginx.confをいじる

nginx.confにstaticファイルのディレクトリを登録する。


/etc/nginx/nginx.conf

server{

# 〜中略〜
location /static {
alias /home/ec2-user/your_project/static;
#settings.pyで設定したのと同じ場所を記述
}
# 〜以下略〜
}


パーミッション変更

ここでnginxとgunicornを再起動する。

$ sh your_project.sh stop

Stopping server...
$ service nginx restart
Stopping nginx: [ OK ]
Starting nginx: [ OK ]
$ sh your_project.sh start
Starting server...

するととpermission deniedが出た。これはec2-userにotherからの権限がないせいだった。

参考によると、このディレクトリに移動する権限が必要らしい。

/home/でec2-userに権限を与える。

$ ls -l

drwx------ 5 ec2-user ec2-user 4096 Oct 6 04:19 ec2-user
$ chmod o+x ec2-user
$ ls -l
drwx-----x 5 ec2-user ec2-user 4096 Oct 6 04:19 ec2-user

gunicornを再起動すると無事にstaticファイルにアクセスできて終了。


参考

EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする

EC2サーバにPython3環境構築

シェルスクリプトでサーバーを起動、停止する

Django での static files の扱い方まとめ

Nginxでつくる、どシンプルな静的コンテンツサーバ