Djangoデプロイ（Nginx, Gunicorn, Ubuntu, docker）

Djangoで作成したWebアプリケーションをUbuntuサーバーにとりあえずデプロイする方法です。
Dockerで構築した場合です。
セキュリティ設定等は、考慮してません。
# 構成
![構成2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770088/2e704385-96de-84c1-b9f6-6fa39912c7ef.png)
# 前準備
manage.pyのrunserverを使用していた環境から、settings.pyを書き換えます。
DEBUGをFalseにすると、STATIC_URLからSTATIC_ROOTに変わるようです。
python3 manage.py collectstaticを実行した際に、static関連のファイルが（管理者サイトのstaticも）STATIC_ROOTにコピーされます。
通常、Nginxの設定で、staticファイルは、/usr/share/nginx/html/staticからレスポンスするように設定しますが、今回は、Nginxのコンテナの/usr/share/nginx/html/staticとBASE_DIR / 'static'をバインドマウントします。
```python:mysite/settings.py
#DEBUG = True
DEBUG = False
STATIC_ROOT = BASE_DIR / 'static'                                          
#STATIC_ROOT = '/usr/share/nginx/html/static'
```
.gitignoreを以下の様に記述して、PCで作成したWebアプリケーションをGitHubにコードをプッシュして下さい。
```.gitignore
*.pyc
*~
/.vscode
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
```
# サーバー側前準備
ubuntuサーバーにpythonのpip,venvとgitをインストールします。
ubuntuは、始めからsudoが使用できますが、sudoが使えない場合は、以下のコマンドでsudoに追加後、一度、ログアウト/ログインして下さい。
```
su -
apt install sudo
usermod -aG sudo user_name
```
```bash
sudo apt install python3-pip
sudo apt install python3-venv
sudo apt install git
```
sudo権限を削除する場合
```
sudo deluser user_name sudo
```
# Docker Engineインストール
ubuntuサーバーはサーバーインストール時にDockerもインストールすることを指定できますが、インストールしなかった場合、以下のコマンドでインストールします。
まず、次のコマンドを実行して、競合するパッケージをすべてアンインストールします。
```
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
```
Dockerのaptリポジトリを設定します。
```
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
```
Docker パッケージをインストールします。
```
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
hello-world イメージを実行して、Docker エンジンのインストールが成功したことを確認します。
```
sudo docker run hello-world
```
余計なコンテナ、イメージを削除するには
```
sudo docker container ls -a
sudo docker container rm <CONTAINER ID>
sudo docker image rm hello-world
```
# Git clone
サーバーの任意のディレクトリにGithubにプッシュしたアプリケーションをクローンします。
GITHUB-ACCOUNT：githubのアカウント名
REPOSITORY：このアプリのリポジトリ名
```bash
git clone https://github.com/GITHUB-ACCOUNT/REPOSITORY.git
```
以降、作成されたREPOSITORYフォルダで作業します。
```
cd REPOSITORY
```
# Python仮想環境作成
Djangoをインストールするための仮想環境を作成します。
仮想環境フォルダ名は、myvenvとしています。
```
python3 -m venv myvenv
```
# Dangoインストールと設定
仮想環境を有効にして、Djangoをインストールして、マイグレーションと管理者ユーザーを作成します。
YOUR-APP：このアプリの名前
```
. myvenv/bin/activate
python3 -m pip install django
python3 manage.py migrate
python3 manage.py migrate YOUR-APP
python3 manage.py createsuperuser
```
staticファイルを集めます。
```
python3 manage.py collectstatic
```
仮想環境から抜けます。
```
deactivate
```
# requirements.txtの作成
PythonコンテナにDjangoとGunicornをインストールするためのrequirements.txtを作成します。
バージョンは指定してません。
```requirements.txt
Django
gunicorn
```
# Nginx設定ファイルの作成
Nginxにアクセスがあった際にGunicorn経由Djangoへ転送されるように設定します。
staticフォルダは、Nginxが応答するようにします。
conf.dフォルダを作成し、conf.dフォルダに入ります。
```
mkdir conf.d
cd conf.d
```
設定ファイルを作成します。
Nginxは、/etc/nginx/conf.dにある拡張子.confファイルを設定ファイルにincludeしています。
このconf.dとコンテナ内の/etc/nginx/conf.dをバインドマウントすることで、設定ファイルを読み込ませます。
```gunicorn.conf
# Gunicornの8000番ポートとつなぐ設定
# ここのgunicornをあとのproxy_passのURLに記載する
upstream gunicorn {
# pythonのところは、コンテナ名を記載する
    server python:8000;
}

server {
    listen 80;
    # この<SERVER_NAME or IP ADDRESS>へのアクセスの時に設定が有効になる
    server_name <SERVER_NAME or IP ADDRESS>;

    # /の場合
    location / {
        proxy_pass http://gunicorn;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }
    
    # /staticの場合、こちらのディレクトリから応答される
    location /static {
	    alias /usr/share/nginx/html/static;
    }
}
```
# Dockerfileの作成
PythonコンテナにDjangoとGunicornをインストールするためのDockerファイルを作成します。
ディレクトリを戻ります。
```
cd ..
```
### Dockerファイルの内容
python3.10のイメージをベースにします
作業ディレクトリをcodeとします
作業ディレクトリに、requirements.txtをコピーします
イメージビルド時に、DjangoとGunicornをインストールします
コンテナ起動時に、Gunicornを実行します
```Dockerfile:Dockerfile
FROM python:3.10
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "mysite.wsgi"]
```
# compose.yaml
PythonコンテナとNginxコンテナを作成するための、compose.yamlファイルを作成します。
### pythonコンテナ
カレントフォルダにあるDockerファイルを元にPythonコンテナのイメージを作成します
カレントフォルダと作業フォルダをバインドマウントします
### nginxコンテナ
nginxのイメージを元にコンテナを作成します。
ホストのポート番号80とコンテナ内のポート番号80を紐付けます。
ホストのカレントフォルダにあるstaticフォルダとコンテナ内の/usr/share/nginx/html/staticフォルダをバインドマウントします。
ホストのカレントフォルダにあるconf.dフォルダとコンテナ内の/etc/nginx/conf.dフォルダをバインドマウントします。
```compose.yaml
services:
  python:
    build: .
    volumes:
      - .:/code
  nginx:
    image: nginx
    ports:
      - "80:80"
    volumes:
      - ./static:/usr/share/nginx/html/static
      - ./conf.d:/etc/nginx/conf.d
```
# コンテナの作成
以下のコマンドでコンテナを作成します。
```
sudo docker compose up -d
```
コンテナが作成されたら、以下のURLにアクセスして下さい。
http://&lt;SERVER_NAME or IP ADDRESS&gt;
コンテナを使い終わったら、以下のコマンドでコンテナを停止・削除します。
```
sudo docker compose down
```
イメージを削除する場合
```
sudo docker image ls
sudo docker image rm <REPOSITORY>
```
コンテナを停止と同時にイメージを削除する場合
```
sudo docker compose down --rmi all
```