プログラミング

docker-composeでDjangoのapiサーバとwebsocketサーバをnginxで構築する方法

Djangoでapiサーバ構築

今回は、pythonのフルスタックwebフレームワークDjangoを使って、apiサーバとwebsocketサーバをnginxで構築する方法について書きます。docker-composeのversion3を使った際の記事が少なかったので、今回は自分が開発で使っている構成をご紹介したいと思います。

使うもの

  • docker
  • docker-compose
  • Django
  • Nginx
  • MySQL
  • Redis

docker-compose

docker-compose.yml

version: '3'
services:
db:
image: mysql:5.7
hostname: db
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
restart: always
volumes:
- db-data:/var/lib/mysql
ports:
- "3306:3306"
environment:
- MYSQL_DATABASE=(your_db_name)
- MYSQL_ROOT_PASSWORD=(your_db_password)
- MYSQL_ROOT_HOST=%
networks:
- default

redis:
image: redis:alpine
restart: always
expose:
- "6379"
command: redis-server --appendonly yes
networks:
- default

app:
build:
context: .
command: sh -c "sleep 10; python manage.py makemigrations; python manage.py migrate; python manage.py collectstatic --noinput; nohup gunicorn (your_app_name).wsgi -b 0.0.0.0:8000 & daphne -b 0.0.0.0 -p 8001 (your_app_name).asgi:application"
restart: always
expose:
- "8000"
- "8001"
volumes:
- .:/webapp
- static:/var/www/static
depends_on:
- db
- redis
networks:
- default

web:
image: nginx:latest
ports:
- "8000:8000"
volumes:
- static:/var/www/static
- public-data:/webapp/public
- tmp-data:/webapp/tmp
- ./settings/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- default

volumes:
static:
public-data:
tmp-data:
db-data:

networks:
default:

 

docker-composeファイルでは、mysql,app,nginx,redisのdockerコンテナをまとめて起動しています。

docker-compose build

docker-compose up

 

でDockerfileのビルドとコンテナの立ち上げが完了します。

中身について

db:
image: mysql:5.7
hostname: db
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
restart: always
volumes:
- db-data:/var/lib/mysql
ports:
- "3306:3306"
environment:
- MYSQL_DATABASE=(your_db_name)
- MYSQL_ROOT_PASSWORD=(your_db_password)
- MYSQL_ROOT_HOST=%
networks:
- default

redis:
image: redis:alpine
restart: always
expose:
- "6379"
command: redis-server --appendonly yes
networks:
- default

 

dbコンテナではmysqlの基本的な設定を定義しています。redisコンテナはただ起動するだけです。(djangoのwebsocketサーバを起動する為に必要なコンテナです。)

web:
image: nginx:latest
ports:
- "8000:8000"
volumes:
- static:/var/www/static
- public-data:/webapp/public
- tmp-data:/webapp/tmp
- ./settings/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- default

 

webコンテナはnginxのwebサーバコンテナで、ホストの8000番ポートとコンテナの8000版ポートを繋げています。nginxの設定はnginx.confというファイルに別途記述する必要があるので、あとで説明します。

app:
build:
context: .
command: sh -c "sleep 10; python manage.py makemigrations; python manage.py migrate; python manage.py collectstatic --noinput; nohup gunicorn (your_app_name).wsgi -b 0.0.0.0:8000 & daphne -b 0.0.0.0 -p 8001 (your_app_name).asgi:application"
restart: always
expose:
- "8000"
- "8001"
volumes:
- .:/webapp
- static:/var/www/static
depends_on:
- db
- redis
networks:
- default

 

appコンテナはdjangoのアプリケーションが動作するコンテナです。8000版ポート(webサーバ用)、8001番ポート(websocket用)を解放しています。nginx.confでwebコンテナにきたアクセスをこのコンテナに飛ばすようにしています。appコンテナのcommandは、djangoの起動に必要なコマンド等です。makemigrationでmigrationファイルを作成し、migrateでデータベースに反映させています。collectstaticは静的ファイルを配置し、gunicornはdjangoのwebサーバを立ち上げる為のコマンドです。daphneはdjangoのwebsocketサーバを立ち上げる為のコマンドです。

nginx.conf

upstream webserver {
server app:8000;
}

upstream websocket {
server app:8001;
}

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

server {
listen 8000;
server_name localhost;
keepalive_timeout 5;
client_max_body_size 1m;

client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

add_header Strict-Transport-Security 'max-age=31536000';
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

error_page 500 502 503 504 /50x.html;

location /static {
alias /var/www/static;
}

location / {
proxy_pass http://webserver/;
}

location /ws/ {
proxy_pass http://websocket/ws/;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

location = /50x.html {
root /usr/share/nginx/html;
}
}

 

nginx.confではnginxの設定を記述します。ここではルートのurlでnginxのwebサーバにアクセスがきた場合、djangoのappコンテナの8000番ポート(webサーバ)にアクセスを送ります。nginxに/ws/のアクセスがきた場合、djangoコンテナの8001番ポート(webソケット)にアクセスを振り分けます。

振り分けられたappコンテナでは、gunicornコマンドによってwebサーバが立ち上がっており、daphneコマンドによってwebsocketサーバも立ち上がっているので、この設定でwebserverとwebsocketをどとらも起動することができます。

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

 

websocketを扱う際に注意しなければならないのは、上に書いた部分を記述しないとwebsocketの通信としてnginxが解釈してくれない点です。websocketを振り分ける時はこのコードを記述しましょう。

Djangoの設定

最後にdjangoのアプリケーション内で設定しなければならない項目についてご紹介します。なお、ここではapiの仕組みとしてdjango REST framework、websocketの仕組みとしてchannelsを使うことを想定しています。あくまで以下の設定項目はそれらのライブラリを使用する際に必要になるものに過ぎないという点はご了承ください。

 

settings.py

// redisコンテナとの連携
ASGI_APPLICATION = '(your_app_name).routing.application'

CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('redis', 6379)],
},
},
}

// データベースのコンテナと連携
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '(your_db_name)',
'USER': '(your_db_user_name)',
'PASSWORD': '(your_db_password)',
'HOST': 'db',
'PORT': 3306,
'OPTIONS': {'charset': 'utf8mb4'},
}
}

 

まとめ

以上がdjangoをnginxで動かす為の設定になります。dockerやdjangoの基本的な仕組みがわかっている人は、コードの部分だけでも参考にして見てください。

ABOUT ME
gitackt
温泉と餃子が好きです。