#1.この記事の内容
Webアプリケーション開発のお勉強 #1では,実装するWebサーバ及びアプリケーションの構成を記載しました.
本記事ではこの環境の構築手順を記載します.
下図は,実装するWebアプリケーションの構成図の再掲です.
※GitHubの環境構築手順に補足説明を追記した形となります.
#2.環境構築
-
用語の定義
用語 定義 <path/to/project> 環境を構築する作業ディレクトリのルート
##2-1.全体の流れ
2-2.ホストPCへのパッケージインストール
↓
2-3.docker-composeにDjangoサーバを追加
↓
2-4.docker-composeにPostgreSQLサーバを追加
↓
2-5.docker-composeにNginxサーバを追加
##2-2.ホストPCへのパッケージインストール
サーバ起動の為のdocker-compose及び,Djangoプロジェクト構築等の為のvirtualenvをホストPCへインストールします.
$ sudo apt install python3-pip docker-compose
$ sudo -H pip3 install --upgrade pip
$ sudo -H pip3 install virtualenv
##2-3.docker-composeにDjangoサーバを追加
Djangoアプリケーションサーバはdocker-compose.ymlからDockerfileを呼び出してイメージのビルド及びコンテナの起動を行います.
Djangoプロジェクトの作成はvirtualenvを用いた仮想環境上で実施します.
###2-3-1.Djangoプロジェクトの作成
$ cd <path/to/project>
$ virtualenv venv
$ source venv/bin/activate
(venv)$ pip3 install django
(venv)$ mkdir django_project
(venv)$ cd django_project
(venv)$ django-admin startproject project .
(venv)$ tree .
.
├── manage.py
└── project
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
(venv)$ deactivate
###2-3-2.Docker関連の設定ファイルの追加と編集
Djangoプロジェクト作成時はデフォルトでdjango_project/project/settings.pyにSECRET_KEYが記述されます.
運用環境に記述するSECRET_KEYは社内やチーム内などに限定し暗号化するなどで機密性を持たせた上で管理すべきですが,開発環境でも機密性を維持することは開発効率を低下させてしまう場合があります.
そこで,今回の実装では,django_project/project/local_settings.py
に開発用のSECRET_KEYを記述する仕組みを導入します.
SECRET_KEYはdjangoモジュールのget_random_secret_key()関数を用いて生成することができます(GitHubにサンプルコードを登録しています).
$ cd <path/to/project>/django_project
$ touch Dockerfile
$ touch requirements.txt
$ cd ..
$ touch docker-compose.yml
$ touch .env.dev
$ vim django_project/project/settings.py
Dockerfileの中身
FROM python:3.9.7-alpine
WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
COPY . .
requirements.txtの中身
Django
docker-compose.ymlの中身
version: '3.7'
services:
web:
build: ./django_project
command: python manage.py runserver 0.0.0.0:8000
volumes:
- ./django_project/:/usr/src/app/
ports:
- 8000:8000
env_file:
- ./.env.dev
.env.devの中身
DEBUG=True
ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
django_project/project/settings.pyの編集内容
@@ -10,8 +10,14 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
+import os
from pathlib import Path
+try:
+ from .local_settings import SECRET_KEY
+except ImportError:
+ pass
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -19,13 +25,10 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'django-insecure-np7oaeipi%hbg9hd^jg+*$8dc!d(*5cnbjzid1-m-kp^fu1fbm'
-
# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+DEBUG = os.environ.get("DEBUG")
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS").split(" ")
# Application definition
###2-3-3.ロケットの起動確認
下記コマンドでDockerイメージのビルド,コンテナ起動を行い,http://localhost:8000 へアクセスするとDjangoのロケットが表示されることが確認できます.
$ cd <path/to/project>
$ docker-compose build
$ docker-compose up -d
起動しているコンテナを確認すると「xxx_web_1」が起動されます.
「xxx」の部分はプロジェクト名(のディレクトリ名)が入ります.
本記事の執筆では,プロジェクト名を「test」として動作確認したため,「test_web_1」となります.
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------
test_web_1 python manage.py runserver ... Up 0.0.0.0:8000->8000/tcp,:::8000->8000/tcp
##2-4.docker-composeにPostgreSQLサーバを追加
###2-4-1.PostgreSQLサーバの設定追加
$ cd <path/to/project>
$ vim .env.dev
$ vim docker-compose.yml
$ vim django_project/Dockerfile
$ vim django_project/requirements.txt
$ vim django_project/project/settings.py
$ touch django_project/entrypoint.sh
.env.devの編集
@@ -1,2 +1,14 @@
DEBUG=True
ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
+
+SQL_DATABASE=db_name
+SQL_USER=user_name
+SQL_PASSWORD=password
+SQL_HOST=db
+SQL_PORT=5432
+
+POSTGRES_USER=user_name
+POSTGRES_PASSWORD=password
+POSTGRES_DB=db_name
+
+DATABASE=postgres
docker-compose.ymlの編集
@@ -10,3 +10,15 @@ services:
- 8000:8000
env_file:
- ./.env.dev
+ depends_on:
+ - db
+
+ db:
+ image: postgres:13.4-alpine
+ volumes:
+ - postgres_data:/var/lib/postgresql/data/
+ env_file:
+ - ./.env.dev
+
+volumes:
+ postgres_data:
+ ```
</div>
</details>
<details><summary>django_project/Dockerfileの編集</summary>
<div>
@@ -5,9 +5,13 @@ WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
+RUN apk update \
- && apk add postgresql-dev gcc python3-dev musl-dev
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
COPY . .
+ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
</div>
</details>
<details><summary>django_project/requirements.txtの編集</summary>
<div>
@@ -1 +1,2 @@
Django
+psycopg2-binary
</div>
</details>
<details><summary>django_project/project/settings.pyの編集</summary>
<div>
@@ -78,8 +78,12 @@ WSGI_APPLICATION = 'project.wsgi.applica
DATABASES = {
'default': {
-
'ENGINE': 'django.db.backends.sqlite3',
-
'NAME': BASE_DIR / 'db.sqlite3',
-
'ENGINE': 'django.db.backends.postgresql_psycopg2',
-
'NAME': os.environ.get("SQL_DATABASE"),
-
'USER': os.environ.get("SQL_USER"),
-
'PASSWORD': os.environ.get("SQL_PASSWORD"),
-
'HOST': os.environ.get("SQL_HOST"),
-
}
'PORT': os.environ.get("SQL_PORT"),
}
</div>
</details>
<details><summary>django_project/entrypoint.shの中身</summary>
<div>
#!/bin/sh
if [ "$DATABASE" = "postgres" ]
then
echo "Waiting for postgres..."
while ! nc -z $SQL_HOST $SQL_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
fi
exec "$@"
</div>
</details>
###2-4-2.PostgreSQLサーバ動作確認
下記コマンドでビルド,起動を行います.
$ docker-compose build
$ docker-compose up -d
起動しているコンテナにデータベースサーバ「xxx_db_1」が追加されます.
$ docker-compose ps
Name Command State Ports
test_db_1 docker-entrypoint.sh postgres Up 5432/tcp
test_web_1 /usr/src/app/entrypoint.sh ... Up 0.0.0.0:8000->8000/tcp,:::8000->8000/tcp
マイグレートしてリストを確認すると,以下のようにデータベースのリストを表示できます.
$ docker-compose exec web python manage.py migrate --no-input
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
$ docker-compose exec db psql --username=user_name --dbname=db_name
psql (13.4)
Type "help" for help.
db_name=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-----------+----------+------------+------------+-------------------------
db_name | user_name | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | user_name | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | user_name | UTF8 | en_US.utf8 | en_US.utf8 | =c/user_name +
| | | | | user_name=CTc/user_name
template1 | user_name | UTF8 | en_US.utf8 | en_US.utf8 | =c/user_name +
| | | | | user_name=CTc/user_name
##2-5.docker-composeにNginxサーバを追加
###2-5-1.Gunicornの設定
$ cd
$ vim docker-compose.yml
$ vim django_project/requirements.txt
$ vim django_project/Dockerfile
<details><summary>docker-compose.ymlの編集</summary>
<div>
@@ -3,9 +3,7 @@ version: '3.7'
services:
web:
build: ./django_project
- command: python manage.py runserver 0.0.0.0:8000
- volumes:
-
- ./django_project/:/usr/src/app/
- command: gunicorn project.wsgi:application --bind 0.0.0.0:8000
ports:- 8000:8000
env_file:
- 8000:8000
</div>
</details>
<details><summary>django_project/requirements.txtの編集</summary>
<div>
@@ -1,2 +1,3 @@
Django
psycopg2-binary
+gunicorn
</div>
</details>
<details><summary>django_project/Dockerfileの編集</summary>
<div>
@@ -1,4 +1,4 @@
-FROM python:3.9.7-alpine
+FROM python:3.9.7-alpine as builder
WORKDIR /usr/src/app
@@ -9,9 +9,36 @@ RUN apk update
&& apk add postgresql-dev gcc python3-dev musl-dev
RUN pip install --upgrade pip
-COPY ./requirements.txt .
-RUN pip install -r requirements.txt
+RUN pip install flake8
COPY . .
-ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
+COPY ./requirements.txt .
+RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
+
+
+FROM python:3.9.7-alpine
+
+RUN mkdir -p /home/app
+
+RUN addgroup -S app && adduser -S app -G app
+
+ENV HOME=/home/app
+ENV APP_HOME=/home/app/web
+RUN mkdir ${APP_HOME}
+WORKDIR ${APP_HOME}
+
+RUN apk update && apk add libpq
+COPY --from=builder /usr/src/app/wheels /wheels
+COPY --from=builder /usr/src/app/requirements.txt .
+RUN pip install --no-cache /wheels/*
+
+COPY ./entrypoint.sh $APP_HOME
+
+COPY . $APP_HOME
+
+RUN chown -R app:app $APP_HOME
+
+USER app
+
+ENTRYPOINT ["/home/app/web/entrypoint.sh"]
</div>
</details>
###2-5-2.Nginxの設定追加
$ cd
$ vim docker-compose.yml
$ mkdir nginx
$ touch nginx/Dockerfile
$ touch nginx/nginx.conf
$ vim django_project/project/settings.py
$ vim django_project/Dockerfile
<details><summary>docker-compose.ymlの編集</summary>
<div>
@@ -4,8 +4,10 @@ services:
web:
build: ./django_project
command: gunicorn project.wsgi:application --bind 0.0.0.0:8000
- volumes:
-
ports:
- static_volume:/home/app/web/static
-
- 8000:8000
-
- 8000
env_file:
- ./.env.dev
depends_on:
@@ -18,5 +20,16 @@ services:
env_file:
- ./.env.dev -
nginx:
-
build: ./nginx
-
volumes:
-
- static_volume:/home/app/web/static
-
ports:
-
- 1317:80
-
depends_on:
-
- web
volumes:
postgres_data:
- static_volume:
</div>
</details>
<details><summary>nginx/Dockerfileの内容</summary>
<div>
FROM nginx:1.21.3-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
</div>
</details>
<details><summary>nginx/nginx.confの内容</summary>
<div>
upstream project {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://project;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /home/app/web/static/;
}
}
</div>
</details>
<details><summary>django_project/project/settings.pyの編集</summary>
<div>
@@ -125,6 +125,7 @@ USE_TZ = True
https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
+STATIC_ROOT = os.path.join(BASE_DIR, "static")
Default primary key field type
https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
</div>
</details>
<details><summary>django_project/Dockerfileの編集</summary>
<div>
@@ -26,6 +26,7 @@ RUN addgroup -S app && adduser -S app -G
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir ${APP_HOME}
+RUN mkdir ${APP_HOME}/static
WORKDIR ${APP_HOME}
RUN apk update && apk add libpq
</div>
</details>
###2-5-3.動作確認
下記コマンドでイメージのビルド,コンテナの起動を行い,http://localhost:1317 へアクセスすると,Djangoのロケットが表示されます.
先ほどと異なり,アクセス先のポートが8000から1317に変更しており,これはブラウザからはNginxサーバにアクセスし,NginxサーバからGunicornを経由してDjango Webサーバからページを取得していることとなります.
$ docker-compose build
$ docker-compose up -d
起動しているコンテナは,「xxx_nginx_1」が追加されていることが確認できます.
$ docker-compose ps
Name Command State Ports
test_db_1 docker-entrypoint.sh postgres Up 5432/tcp
test_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:1317->80/tcp,:::1317->80/tcp
test_web_1 /home/app/web/entrypoint.s ... Up 0.0.0.0:49153->8000/tcp,:::49153->8000/tcp
#3.さいごに
docker-composeを利用したWebサーバのベース環境の構築手順を記載しました.
次回以降,Bootstrapの導入と機械学習アプリケーションの実装について記載を進める予定です.
#4.関連リンク
* [Webアプリケーション開発のお勉強 目次](https://qiita.com/ryoma-jp/items/1a0a438313dcb30ef6fc)
* [GitHubのReference](https://github.com/ryoma-jp/AI_Dashboard#reference)を参照