EC2へのDjangoデプロイで無茶苦茶時間食ったので、備忘録がてら、トラブル各種まとめてみます。
ちなみにdjango童貞です。「こうしたらええんやで」っていう諸先輩方いらっしゃいましたらコメントいただければ喜びます。
デプロイ一連の流れ
- EC2インスタンス作成
- ポート開放
- SSH接続で環境整備
- プロジェクトファイルアップロード
- セッティングファイルあれこれ
- 完成
EC2インスタンス作成
なんか二種類ありますが、違いもよくわかりませんし、多分どっちでもいいです。好きな方で。
セキュリティグループの編集(ポート開放)
インバウンドの方をこんな感じの設定にすればOKです。
ちなみに作成時に編集しなくてもあとから変更できます。
あとは大体ディフォルトのまま進めてOKです。
SSH接続
事前にEC2キーペアを作っていたらそれを紐づけ、そうじゃなければEC2インスタンス生成時に項目があるので、鍵ファイル(.pem)をDLしてローカルに保持しておきます。
SSHクライアントは普段使っているものでOKです。
今回はPycharm組み込みのSSHクライアントを例に接続方法を解説。
サーバーの構成ボタンを押してさらに進みます。
- 型:SFTP
- ホスト:EC2インスタンスのパブリックDNS(IPv4)
- ユーザー名:ec2-user
- 認証:Key pair
- Private key path:EC2コンソールからDLした(.pem)ファイルのパス
ここまで入力して接続テストして、OKならルートパスとかはオートで入力できます。
マッピング(やると便利)
ここ設定しておくとPycharmのプロジェクト(ローカル)とリモートのサーバーを自動で同期できます(多分)
ローカルで編集・保存するたびに指定されたリモートサーバーの対応する位置へアップロードされるようです。
EC2インスタンスの環境整備
SSHで無事接続できたので、必要な環境を整備していきます。
参考: https://qiita.com/pokotsun/items/1272479e36c5146c6609
参考先ではユーザーを作成してますが、管理めんどくさかったのでディフォルトのec2-userのまま環境整備進めました。
ここではyum使ってますが環境によって適宜aptとかに読み替えてください。
yumで下準備
$ sudo -i $ yum update -y $ yum install -y vim git
Python3インストール
$ cd ~ $ sudo yum install -y gcc make zlib1g-dev zlib-devel openssl-devel tk-devel sqlite-devel bzip2 bzip2-devel readline-devel $ wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz $ tar Jxfv Python-3.7.4.tar.xz $ cd Python-3.7.4/ $ ./configure --prefix=/home/ec2-user/.local/python $ make $ make install # シンボリックリンクを貼る $ sudo ln -s ~/.local/python/bin/python3 /usr/local/bin/python $ sudo ln -s ~/.local/python/bin/pip3.7 /usr/local/bin/pip3 $ echo 'export PATH="/home/ec2-user/.local/python/bin:$PATH"' >> ~/.bashrc $ echo 'alias pip=pip3' >> ~/.bashrc # 確認 $ python -V Python 3.7.4 $ pip -V pip 19.0.3 from /home/ec2-user/.local/python/lib/python3.7/site-packages/pip (python 3.7)
プロジェクトファイルアップロード
アップロードはgithub使ってcloneしてもいいですし、Pycharmから普通にアップしてもいいですし、煮るなり焼くなりお好きに。
ただ、モジュールのインストール手動でやると面倒なので「requirements.txt」だけつくっておきます。
ローカルのプロジェクト直下で以下のコマンド。
$ pip freeze > requirements.txt
アップ後、依存関係復元
$ pip install -r requirements.txt
django→settings.pyの編集
本番環境用にsettings.pyを編集する必要があります。
以下の箇所を見つけて編集。
DEBUG = False # True => Falseにする # ローカルホスト、リモートIP、リモートホストを追加 ALLOWED_HOSTS = ['127.0.0.1', 'xx.xx.xxx.xxx', 'ec2-xx-xx-xxx-xxx.ap-northeast-1.compute.amazonaws.com'] # staticファイル関係、必要であれば STATIC_URL = '/static/' # 多分元々こうなってる STATIC_ROOT = os.path.join(BASE_DIR, 'static')
django童貞の僕としてはなぜdjangoのstaticファイルの構成がこんなめんどい感じなのかわからないまま・・・。
とりあえず、開発時にプロジェクト共通のstaticフォルダとか作ってなくて、app直下にstatic作って対応してた方は上記で問題ないと思います。
staticのファイルを集約する
$ python manage.py collectstatic
なぜこんな面倒なことさせるのか知りませんが、app直下のstaticファルダ内のファイルを集約してproject直下のstaticフォルダにコピーするコマンドです。
これやらないとリモートで見たときにstaticファイルが見つからず404になります。
さらに面倒なことにcollectstaticをやってても403になる場合があります。
サーバーミドルウェアインストールと設定
サーバーはnginxです。なうい(別になうくはないのか?)です。
$ sudo amazon-linux-extras install nginx1.12 $ sudo service nginx start
さらにこれも必要なよう。
pip install gunicorn
gunicornはなんかnginxで受け取った処理をさらに中継するのに使うようです。
ここでdjango童貞の僕はこう思いました。
「いや、何でディフォルトのサーバー使わんのや?」
manage.py runserver
でええんちゃうのん?ただただめんどいだけちゃうんか、と。
回答は以下。
参考: https://blog.hirokiky.org/entry/2018/10/06/151830
要約すると、
「なんかわからんけど、とりあえず早いらしい」
なら、まぁ、使っとくか。
nginx→gunicornの流れ
$ sudo vi /etc/nginx/nginx.conf
からの。
# For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; index index.html index.htm; upstream app_server { server 127.0.0.1:8000 fail_timeout=0; } server { ## ここを書き換える listen 80; server_name (EC2のドメイン or IPアドレス); client_max_body_size 6G; # 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; } location /static { alias (アプリケーションのstaticファイルの絶対パスを記入); expires 5h; } # redirect server error pages to the static page /40x.html # error_page 404 /404.html; location = /40x.html { } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ .php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ .php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /.ht { # deny all; #} } }
考えるのめんどくさかったので、設定ファイル全部消してからの完コピです。
マジでありがとうございます。
参考: https://qiita.com/pokotsun/items/1272479e36c5146c6609
サーバーの起動
ここまで設定が完了したらあとはサーバーを立ち上げてアクセスするのみ。
$ sudo service nginx restart $ gunicorn MyAppName.wsgi --bind=0.0.0.0:8000
MyAppNameはプロジェクト直下の最上位アプリケーション名(settings.pyとかが入っているapp)です。
確認してみればわかりますが、wsgi.pyというファイルがあります。
この状態でAWSのEC2コンソールで確認できるパブリックDNSのアドレスへアクセスするとローカルで見ていたのと同じようにdjangoで作ったWebアプリが確認できるはずです。
ちなみにgunicornはこの状態だとSSHの接続を切ると落ちてしまいますので、普段使いで常時待機状態にするならデーモンとして立ち上げる必要があります。
$ gunicorn MyAppName.wsgi --bind=0.0.0.0:8000 -D
-D オプションをつけるだけです。これでバックグラウンド起動になります。
デーモンで走ってるgunicornサーバーをkillするときは以下コマンド
$ pkill gunicorn
nginxを止めるときはこうです。
$ sudo service nginx stop
ちょっとハマったトラブル集
いくつかハマった箇所があるので紹介します。
SQliteのバージョンエラー
django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is required (found 3.7.17).
3.8以上のSQliteのバージョンを要求されます。
SQliteってバージョンもクソもあるんかよ・・・。とか思いながら、調べました。
参考: https://qiita.com/rururu_kenken/items/8202b30b50e3bfa75821
と、まぁ色々弄くり回してという方法もあるようですが、一番簡単なのはこれです。
$ pip install django==2.1
どうやらdjango2.2以上から出現するエラーのようですので、特に2.2にこだわる理由もなかったので僕はdjangoのバージョンを下げることで対応しました。
Staticファイル群の403
CSSとかJSファイルが403でちゃんと動いてないなってなったらこのパターンだと思います。
ec2-userにパーミッションを振る
参考: https://qiita.com/xKxAxKx/items/f43d1bddbc4fb31013b1
$ sudo chmod o+x /home/ec2-user/
これで一発解決。
コメント