0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Webアプリケーション開発のお勉強 #2

Last updated at Posted at 2021-11-12

#1.この記事の内容

Webアプリケーション開発のお勉強 #1では,実装するWebサーバ及びアプリケーションの構成を記載しました.

本記事ではこの環境の構築手順を記載します.
下図は,実装するWebアプリケーションの構成図の再掲です.
 ※GitHubの環境構築手順に補足説明を追記した形となります.

Webアプリケーションの構成

#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

django_rocket.png

##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:

</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:
  •  - static_volume:/home/app/web/static
    
    ports:
  •  - 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)を参照

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?