AWSのEC2(+RDS(+S3))でDjangoアプリケーション(+MySQL)を公開するまで


AWSのEC2インスタンスとRDSインスタンスがある状態からどうすればDjango+Apache(+mod-wsgi)+MySQLでWebアプリを公開できるかです.Webアプリプログラムはあるものとします.なお,情報は2020/1/1時点です.

また,pyenv+Anacondaを使っていますが,この辺はPythonをyum installするとか今時Pipenv使うでしょとかは各自の宗教に合わせてください.

使用したバージョンなど

Python関係

  • Python 3.7.4 (anaconda3-2019.10 使用)
  • pyenv 1.2.15-9-gac246e16
  • Django 3.0.1
  • django-el-pagination 3.2.4
  • django-maintenance-mode 0.14.0
  • django-storages 1.8
  • mod-wsgi 4.7.0
  • mysqlclient 1.4.6

Apache,MySQL Client

$ httpd -v
Server version: Apache/2.4.41 ()
Server built:   Oct 22 2019 22:59:04
$ mysql --version
mysql  Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)

MySQLはバージョン8.0系を使っています.

pyenvとPython3のインストール

pyenvのインストール

デフォルトのpythonは汚したくない.

sudo git clone git://github.com/yyuu/pyenv.git /usr/local/pyenv
% 所有者がsudoはやだ.再帰的に変えてしまう
sudo chown -r ec2-user:ec2-user pyenv

~/.bash_profile を書き換え

export PATH
export PYENV_ROOT="/usr/local/pyenv"
export GOPATH="$HOME/.go"
export PATH="$GOPATH/bin:$PYENV_ROOT/bin:$PYENV_ROOT/bin/pyenv:$PATH"
eval "$(pyenv init -)"

書き換えたら source .bash_profile して読み込む.

Python3のインストール

楽したいのでanacondaいれちゃう.宗教戦争には関わらないです.condaでのインストールは絶対に使わないけど.

# 執筆時点の最新安定版
pyenv install anaconda3-2019.10
# デフォを変える
pyenv global anaconda3-2019.10

Djangoの導入

これは簡単.ただDjangoのバージョンには要注意.後方互換性のない変更もしばしば.

pip install django

その他便利なやつ

% ファイルを扱う
pip install django-storages
% メンテナンスモード
pip install django-maintenance-mode
% s3を扱う
pip install boto3

ウェブサーバ導入

ウェブサーバ導入します.目指せapache+mod-wsgi.

apacheのインストール

sudo yum install httpd
sudo systemctl start httpd
# 確認するなら
sudo systemctl status httpd
# サービスのスタート
sudo systemctl start httpd.service

グローバルIPを指定すればApacheテストページが表示される

Apacheテストページではないものにしたいなら, /etc/httpd/conf/httpd.conf 内を書き換え.

参考にしたページ:
https://qiita.com/saki-engineering/items/5ea8e66b498fc7d4a399
https://miyabi-lab.space/blog/16#200

mod-wsgiの導入

Pythonとapacheをつなぐツール.

インストールのためのコンパイル時にapexとgccが必要になるが,デフォルトでは入っていない.

sudo yum install httpd-devel
sudo yum install gcc

こうすればpipでmod-wsgiは入る

pip install mod_wsgi

連携させる

以下はDjangoで公開するページがある前提.サンプル的なものでも可.

一部参考にしたページ: https://qiita.com/saki-engineering/items/5ea8e66b498fc7d4a399

mod-wsgiの入っている場所を探す.ルートディレクトリに移動してから

$ find -name 'mod_wsgi*.so' 2> /dev/null
./usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so

よって /usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so にある.

Amazon Linux 2なら多分 /etc/httpd/conf/httpd.conf の最後に

# Load config files in the "/etc/httpd/conf.d" directory, if any.
IncludeOptional conf.d/*.conf

と書いてあるはずなので, /etc/httpd/conf.d/myconf.conf

LoadModule wsgi_module /usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so

WSGIScriptAlias / (wsgi.pyの置いた場所)
WSGIPythonPath (Djangoで書いたwebappプログラムのルートディレクトリ)
WSGIPythonHome (実行したいPythonの実行ファイルの親ディレクトリ; 例: /usr/local/pyenv/versions/anaconda3-2019.10)
Alias /static/ (Djangoで書いたwebappプログラムのstaticファイルのディレクトリ)

<Directory (Djangoで書いたwebappプログラムのルートディレクトリ)>
    <Files wsgi.py>
        Order deny,allow
        Require all granted
    </Files>
</Directory>
<Directory (Djangoで書いたwebappプログラムのstaticファイルのディレクトリ)>
    Require all granted
</Directory>

とかく. sudo service httpd restart する.

前やったときは WSGIPythonPath を指定しなくてよかったのですがなぜでしょう…

MySQLの導入

RDSですでにMySQL8.0のサーバ立ち上げ済みとします.

MySQL 8.0用のクライアントを入れる
参考にしたページ: https://dev.classmethod.jp/cloud/aws/amazon-linux2-mysqlclient/

# リポジトリ追加
$ sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
# 標準の状態で8.0の設定ですが一応有効に
$ sudo yum-config-manager --enable mysql80-community
# Mysql Client Install
$ sudo yum install -y mysql-community-client
$ mysql --version
mysql  Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)

サーバ始動

$ whereis mysql_config
mysql_config:

実はこの時点では mysql_config がないと怒られる.

$ sudo yum install mysql-devel

すると

$ whereis mysql_config
mysql_config: /usr/bin/mysql_config /usr/share/man/man1/mysql_config.1.gz

そしてPythonからmysqlクライアントにアクセスするためにpipでインストール

pip install mysqlclient

無限ページネーションしたい

$ pip install django-el-pagination

で入るやつは古かった.2年くらいリリースされていない.じゃあgitから落とせばいい(メンテナンスはきちんとされていてDjango3.0にもすぐに対応されている)

$ git clone https://github.com/shtalinberg/django-el-pagination.git
$ cd django-el-pagination/
$ pip install -e .

しかし,これでやっても動こうとするが,webサイトにアクセスできない. ModuleNotFoundError el_pagination となってしまう.リンクがうまく張られないことが原因?それともeditableモードなのが原因?

じゃあgitから直接pip installしよう.

pip install git+https://github.com/shtalinberg/django-el-pagination.git

これでできた.

その他の必要な設定(settings.py)は
https://django-el-pagination.readthedocs.io/en/latest/start.html
を参照.

swap領域の確保

EC2インスタンスのデフォルトのメモリのサイズはありえないほど小さいので必須.

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
2048+0 レコード入力
2048+0 レコード出力
2147483648 バイト (2.1 GB) コピーされました、 31.4376 秒、 68.3 MB/秒
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
スワップ空間バージョン 1 を設定します。サイズ = 2 GiB (2147479552 バイト)
ラベルはありません, UUID=82de405a-d7ef-4ae3-ba93-16baa38c6e2c
$ sudo swapon /swapfile
# 確認
swapon -s
ファイル名             タイプ       サイズ   使用済み    優先順位
/swapfile                               file        2097148 0   -2
# 起動時にswap領域が有効になるように
$ sudo vi /etc/fstab
# 追加
# /swapfile swap swap defaults 0 0

参考: https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-memory-swap-file/

検索避け

/var/www/html/robots.txt

User-agent : *
Disallow : /

を作成,保存する