AWSのEC2にdjangoデプロイ時のトラブルシューティング



EC2へのDjangoデプロイで無茶苦茶時間食ったので、備忘録がてら、トラブル各種まとめてみます。

ちなみにdjango童貞です。「こうしたらええんやで」っていう諸先輩方いらっしゃいましたらコメントいただければ喜びます。

デプロイ一連の流れ

  • EC2インスタンス作成
  • ポート開放
  • SSH接続で環境整備
  • プロジェクトファイルアップロード
  • セッティングファイルあれこれ
  • 完成

EC2インスタンス作成

EC2インスタンス作成
EC2インスタンス作成
AMI選択
AMI選択

なんか二種類ありますが、違いもよくわかりませんし、多分どっちでもいいです。好きな方で。

セキュリティグループの編集(ポート開放)

セキュリティグループ
セキュリティグループ

インバウンドの方をこんな感じの設定にすればOKです。
ちなみに作成時に編集しなくてもあとから変更できます。

あとは大体ディフォルトのまま進めてOKです。

SSH接続

事前にEC2キーペアを作っていたらそれを紐づけ、そうじゃなければEC2インスタンス生成時に項目があるので、鍵ファイル(.pem)をDLしてローカルに保持しておきます。

SSHクライアントは普段使っているものでOKです。

今回はPycharm組み込みのSSHクライアントを例に接続方法を解説。

リモートサーバーの構成
リモートサーバーの構成

サーバーの構成ボタンを押してさらに進みます。

SSH設定
SSH設定
  • 型:SFTP
  • ホスト:EC2インスタンスのパブリックDNS(IPv4)
  • ユーザー名:ec2-user
  • 認証:Key pair
  • Private key path:EC2コンソールからDLした(.pem)ファイルのパス

ここまで入力して接続テストして、OKならルートパスとかはオートで入力できます。

マッピング(やると便利)

ここ設定しておくとPycharmのプロジェクト(ローカル)とリモートのサーバーを自動で同期できます(多分)

ローカルで編集・保存するたびに指定されたリモートサーバーの対応する位置へアップロードされるようです。

Pycharm SSH マッピング
Pycharm SSH マッピング
SSHターミナルで接続成功
SSHターミナルで接続成功

EC2インスタンスの環境整備

SSHで無事接続できたので、必要な環境を整備していきます。
参考: https://qiita.com/pokotsun/items/1272479e36c5146c6609

参考先ではユーザーを作成してますが、管理めんどくさかったのでディフォルトのec2-userのまま環境整備進めました。

ここではyum使ってますが環境によって適宜aptとかに読み替えてください。

yumで下準備

Python3インストール

プロジェクトファイルアップロード

アップロードはgithub使ってcloneしてもいいですし、Pycharmから普通にアップしてもいいですし、煮るなり焼くなりお好きに。

ただ、モジュールのインストール手動でやると面倒なので「requirements.txt」だけつくっておきます。

ローカルのプロジェクト直下で以下のコマンド。

アップ後、依存関係復元

django→settings.pyの編集

本番環境用にsettings.pyを編集する必要があります。
以下の箇所を見つけて編集。

django童貞の僕としてはなぜdjangoのstaticファイルの構成がこんなめんどい感じなのかわからないまま・・・。

とりあえず、開発時にプロジェクト共通のstaticフォルダとか作ってなくて、app直下にstatic作って対応してた方は上記で問題ないと思います。

staticのファイルを集約する

なぜこんな面倒なことさせるのか知りませんが、app直下のstaticファルダ内のファイルを集約してproject直下のstaticフォルダにコピーするコマンドです。

これやらないとリモートで見たときにstaticファイルが見つからず404になります。

さらに面倒なことにcollectstaticをやってても403になる場合があります。

サーバーミドルウェアインストールと設定

サーバーはnginxです。なうい(別になうくはないのか?)です。

さらにこれも必要なよう。

gunicornはなんかnginxで受け取った処理をさらに中継するのに使うようです。

ここでdjango童貞の僕はこう思いました。

「いや、何でディフォルトのサーバー使わんのや?」

でええんちゃうのん?ただただめんどいだけちゃうんか、と。
回答は以下。

参考: https://blog.hirokiky.org/entry/2018/10/06/151830

要約すると、

なんかわからんけど、とりあえず早いらしい

なら、まぁ、使っとくか。

nginx→gunicornの流れ

からの。

考えるのめんどくさかったので、設定ファイル全部消してからの完コピです。
マジでありがとうございます。

参考: https://qiita.com/pokotsun/items/1272479e36c5146c6609

サーバーの起動

ここまで設定が完了したらあとはサーバーを立ち上げてアクセスするのみ。

MyAppNameはプロジェクト直下の最上位アプリケーション名(settings.pyとかが入っているapp)です。

確認してみればわかりますが、wsgi.pyというファイルがあります。

この状態でAWSのEC2コンソールで確認できるパブリックDNSのアドレスへアクセスするとローカルで見ていたのと同じようにdjangoで作ったWebアプリが確認できるはずです。

ちなみにgunicornはこの状態だとSSHの接続を切ると落ちてしまいますので、普段使いで常時待機状態にするならデーモンとして立ち上げる必要があります。

-D オプションをつけるだけです。これでバックグラウンド起動になります。

デーモンで走ってるgunicornサーバーをkillするときは以下コマンド

nginxを止めるときはこうです。

ちょっとハマったトラブル集

いくつかハマった箇所があるので紹介します。

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

と、まぁ色々弄くり回してという方法もあるようですが、一番簡単なのはこれです。

どうやらdjango2.2以上から出現するエラーのようですので、特に2.2にこだわる理由もなかったので僕はdjangoのバージョンを下げることで対応しました。

Staticファイル群の403

CSSとかJSファイルが403でちゃんと動いてないなってなったらこのパターンだと思います。

ec2-userにパーミッションを振る

参考: https://qiita.com/xKxAxKx/items/f43d1bddbc4fb31013b1

これで一発解決。