作業中のメモ

よく「計算機」を使って作業をする.知らなかったことを中心にまとめるつもり.

Raspberry Pi 3 Model BでNginx+PostgreSQL+Django環境構築

どうも,筆者です.

前回,Docker のインストールを行った. workspacememory.hatenablog.com

今回は,Dockerfile と docker-compose.yml を使って Nginx+PostgreSQLDjango 環境を構築する. 参考1 参考2

構成

.
│  docker-compose.yml
│
├─django
│      Dockerfile
│      requirements.txt
│      uwsgi.ini
│
├─logs
│      access.log
│      error.log
│      uwsgi.log
│
├─nginx
│  │  Dockerfile
│  │
│  ├─cache
│  ├─conf
│  │      default.conf
│  │      nginx.conf
│  │      uwsgi_params
│  │
│  └─dockerApp
│          nginx
│          wakeup.sh
│
├─postgresql
│      Dockerfile
│
├─src
│  │  manage.py
│  │
│  └─membership_system
│      │  settings.py
│      │  urls.py
│      │  wsgi.py
│      │  __init__.py
│      │
│      └─__pycache__
│              settings.cpython-36.pyc
│              urls.cpython-36.pyc
│              __init__.cpython-36.pyc
│
└─static
    └─admin
        ├─css
        │  │  autocomplete.css
        │  │  base.css
        │  │  changelists.css
        │  │  dashboard.css
        │  │  fonts.css
        │  │  forms.css
        │  │  login.css
        │  │  responsive.css
        │  │  responsive_rtl.css
        │  │  rtl.css
        │  │  widgets.css
        │  │
        │  └─vendor
        │      └─select2
        │              LICENSE-SELECT2.md
        │              select2.css
        │              select2.min.css
        │
        ├─fonts
        │      LICENSE.txt
        │      README.txt
        │      Roboto-Bold-webfont.woff
        │      Roboto-Light-webfont.woff
        │      Roboto-Regular-webfont.woff
        │
        ├─img
        │  │  calendar-icons.svg
        │  │  icon-addlink.svg
        │  │  icon-alert.svg
        │  │  icon-calendar.svg
        │  │  icon-changelink.svg
        │  │  icon-clock.svg
        │  │  icon-deletelink.svg
        │  │  icon-no.svg
        │  │  icon-unknown-alt.svg
        │  │  icon-unknown.svg
        │  │  icon-yes.svg
        │  │  inline-delete.svg
        │  │  LICENSE
        │  │  README.txt
        │  │  search.svg
        │  │  selector-icons.svg
        │  │  sorting-icons.svg
        │  │  tooltag-add.svg
        │  │  tooltag-arrowright.svg
        │  │
        │  └─gis
        │          move_vertex_off.svg
        │          move_vertex_on.svg
        │
        └─js
            │  actions.js
            │  actions.min.js
            │  autocomplete.js
            │  calendar.js
            │  cancel.js
            │  change_form.js
            │  collapse.js
            │  collapse.min.js
            │  core.js
            │  inlines.js
            │  inlines.min.js
            │  jquery.init.js
            │  popup_response.js
            │  prepopulate.js
            │  prepopulate.min.js
            │  prepopulate_init.js
            │  SelectBox.js
            │  SelectFilter2.js
            │  timeparse.js
            │  urlify.js
            │
            ├─admin
            │      DateTimeShortcuts.js
            │      RelatedObjectLookups.js
            │
            └─vendor
                ├─jquery
                │      jquery.js
                │      jquery.min.js
                │      LICENSE-JQUERY.txt
                │
                ├─select2
                │  │  LICENSE-SELECT2.md
                │  │  select2.full.js
                │  │  select2.full.min.js
                │  │
                │  └─i18n
                │          ar.js
                │          az.js
                │          bg.js
                │          ca.js
                │          cs.js
                │          da.js
                │          de.js
                │          el.js
                │          en.js
                │          es.js
                │          et.js
                │          eu.js
                │          fa.js
                │          fi.js
                │          fr.js
                │          gl.js
                │          he.js
                │          hi.js
                │          hr.js
                │          hu.js
                │          id.js
                │          is.js
                │          it.js
                │          ja.js
                │          km.js
                │          ko.js
                │          lt.js
                │          lv.js
                │          mk.js
                │          ms.js
                │          nb.js
                │          nl.js
                │          pl.js
                │          pt-BR.js
                │          pt.js
                │          ro.js
                │          ru.js
                │          sk.js
                │          sr-Cyrl.js
                │          sr.js
                │          sv.js
                │          th.js
                │          tr.js
                │          uk.js
                │          vi.js
                │          zh-CN.js
                │          zh-TW.js
                │
                └─xregexp
                        LICENSE-XREGEXP.txt
                        xregexp.js
                        xregexp.min.js

docker-compose.yml

docker-compose コマンドを実行する際に利用するdocker-compose.ymlファイルを以下に示す.

version: '3.4'

volumes:
    # DBデータの永続化
    postgresql.volume:
        name: postgresql.volume

services:
    # nginxの設定
    nginx:
        # ビルド対象
        build:
            context: ./nginx
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: custom_nginx
        # コンテナ名
        container_name: nginx
        restart: always
        # 環境変数の設定
        environment:
            TZ: Asia/Tokyo
        # ポートの設定(DockerfileのEXPOSEとそろえる)
        ports:
            - "18082:18082"
        # nginxのconfigファイル等の関連付け
        volumes:
            - ./nginx/conf/default.conf:/etc/nginx/conf.d/default.conf:ro
            - ./nginx/cache:/var/cache/nginx
            - ./logs/access.log:/var/log/nginx/access.log
            - ./logs/error.log:/var/log/nginx/error.log
            - ./static:/static:ro
        # 依存関係の記述
        depends_on:
            - django

    # DBの設定
    db:
        # ビルド対象
        build:
            context: ./postgresql
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: custom_postgres
        # コンテナ名
        container_name: postgresql
        restart: always
        environment:
            POSTGRES_DB: djangodb
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: 1234
            POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=ja_JP.UTF-8"
        # ポートの設定(外部には公開しない)
        expose:
            - "5432"
        # 設定ファイルとデータ格納先の関連付け
        volumes:
            - postgresql.volume:/var/lib/postgresql/data

    # djangoの設定
    django:
        # ビルド対象
        build:
            context: ./django
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: django_with_uwsgi
        # コンテナ名
        container_name: django
        restart: always
        # 利用するアプリの関連付け
        volumes:
            - ./src:/code
            - ./static:/static:ro
            - ./logs/uwsgi.log:/var/log/uwsgi.log
        working_dir: /code
        # ポートの設定(外部には公開しない)
        expose:
            - "8081"
        # 依存関係の記述
        depends_on:
            - db

Django の設定

ここでは,Django の設定内容について説明する.

Dockerfile

Django のイメージファイルを作成する際に利用する Dockerfile を以下に示す.

FROM resin/raspberry-pi-alpine:3.6
# Pythonで利用する環境変数の設定
# バイナリレイヤ下での標準出力とエラー出力を抑制
ENV PYTHONUNBUFFERED 1
# アプリケーション用のディレクトリの作成
RUN mkdir /code && mkdir /static
# requirements.txtを追加
ADD requirements.txt /code/

# パッケージ群のインストール
RUN    apk update \
    # タイムゾーンの設定
    && apk add --no-cache bash tzdata pcre-dev \
    && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    # PostgreSQL用のライブラリをインストール
    && apk add --no-cache postgresql-dev \
    # 一時的に必要なパッケージをインストール
    && apk add --no-cache \
           --virtual .build-temp shadow \
           gcc libc-dev linux-headers \
           musl-dev python3-dev libffi-dev libressl-dev \
    # Python3をインストール
    && apk add --no-cache python3 \
    # pip install
    && python3 -m ensurepip \
    && rm -r /usr/lib/python*/ensurepip \
    && pip3 install --upgrade pip setuptools \
    # requirements.txtに記載されたライブラリ群をインストール
    && pip3 install -r /code/requirements.txt \
    # シンボリックリンク
    && if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi \
    # ユーザとグループの追加(Nginxと連動するため統一)
    && useradd -s /sbin/nologin -M -d /dev/null nginx \
    # 一時的に必要だったパッケージを削除
    && apk del .build-temp \
    && rm -rf /root/.cache /var/cache/apk/*

# uWSGIの設定ファイルをコピー
COPY ./uwsgi.ini /uwsgi.ini
# ログ出力先の設定
RUN echo -n > /var/log/uwsgi.log

# 内部で利用するポートの設定
EXPOSE 8081

# コマンド実行
CMD ["uwsgi", "--ini", "/uwsgi.ini", "--logto", "/var/log/uwsgi.log"]

Django で利用する設定ファイル

Django の環境構築時に利用する設定ファイルを以下に示す.

requirements.txt

Django==2.0.7
uwsgi==2.0.17
psycopg2==2.8.2
psycopg2-binary==2.8.2
hashids==1.2.0
django-betterforms==1.2
django-bootstrap4==0.0.6
django-crispy-forms==1.7.2
django-filter==2.1.0
django-extra-views==0.11.0
django-widgets-improved==1.5.0

uwsgi.ini

[uwsgi]
user           = nginx
uid            = nginx
gid            = nginx
chdir          = /code
module         = membership_system.wsgi:application
master         = true
enable-threads = true
thunder-lock   = true
max-requests   = 1000
processes      = 1
threads        = 2
vacuum         = true
socket         = :8081
close-on-exec  = true
die-on-term    = true

docker-compose の設定(対応箇所の抜粋)

対応する docker-compose の設定情報を以下に示す.今回は,8081 番のポートで待ち受ける.このポートは外部に公開しない.

    # djangoの設定
    django:
        # ビルド対象
        build:
            context: ./django
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: django_with_uwsgi
        # コンテナ名
        container_name: django
        restart: always
        # 利用するアプリの関連付け
        volumes:
            - ./src:/code
            - ./static:/static:ro
            - ./logs/uwsgi.log:/var/log/uwsgi.log
        working_dir: /code
        # ポートの設定(外部には公開しない)
        expose:
            - "8081"
        # 依存関係の記述
        depends_on:
            - db

PostgreSQL の設定

ここでは,PostgreSQL の設定内容について説明する. 参考

Dockerfile

Django のイメージファイルを作成する際に利用する Dockerfile を以下に示す.

FROM postgres:latest
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UTF-8

docker-compose の設定(対応箇所の抜粋)

対応する docker-compose の設定情報を以下に示す.今回は,5432 番のポートで待ち受ける.このポートは外部に公開しない.

volumes:
    # DBデータの永続化
    postgresql.volume:
        name: postgresql.volume
    # DBの設定
    db:
        # ビルド対象
        build:
            context: ./postgresql
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: custom_postgres
        # コンテナ名
        container_name: postgresql
        restart: always
        environment:
            POSTGRES_DB: djangodb
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: 1234
            POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=ja_JP.UTF-8"
        # ポートの設定(外部には公開しない)
        expose:
            - "5432"
        # 設定ファイルとデータ格納先の関連付け
        volumes:
            - postgresql.volume:/var/lib/postgresql/data

また,ユーザ名とパスワードは以下のようにした.そのまま利用する際は,適宜変更すること.

項目 内容
ユーザ名 postgres
パスワード 1234

Nginx の設定

ここでは,Nginx の設定内容について説明する.

Dockerfile

Nginx のイメージファイルを作成する際に利用する Dockerfile を以下に示す.

FROM resin/raspberry-pi-alpine:3.6

# Nginxのバージョン指定
ENV NGINX_VERSION 1.14.0
# Nginxのインストール
RUN    apk update \
    && apk add --no-cache pcre-dev openssl-dev bash shadow tzdata \
    && useradd -s /sbin/nologin -M -d /dev/null nginx \
    && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && apk add --no-cache --virtual build-dependencies build-base curl \
    && curl -SLO http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \
    && tar xzvf nginx-${NGINX_VERSION}.tar.gz \
    && cd nginx-${NGINX_VERSION} \
    && ./configure \
           --user=nginx \
           --group=nginx \
           --with-http_ssl_module \
           --with-http_realip_module \
           --with-http_addition_module \
           --with-http_sub_module \
           --with-http_dav_module \
           --with-http_flv_module \
           --with-http_mp4_module \
           --with-http_gunzip_module \
           --with-http_gzip_static_module \
           --with-http_random_index_module \
           --with-http_secure_link_module \
           --with-http_stub_status_module \
           --with-http_auth_request_module \
           --with-threads \
           --with-stream \
           --with-stream_ssl_module \
           --with-http_slice_module \
           --with-mail \
           --with-mail_ssl_module \
           --with-file-aio \
           --with-http_v2_module \
           --prefix=/usr/share/nginx \
           --sbin-path=/usr/local/sbin/nginx \
           --conf-path=/etc/nginx/nginx.conf \
           --pid-path=/var/run/nginx.pid \
           --http-log-path=/var/log/nginx/access.log \
           --error-log-path=/var/log/nginx/error.log \
    && make \
    && make install \
    && echo -n > /var/log/nginx/access.log \
    && echo -n > /var/log/nginx/error.log \
    && cd / \
    && apk del build-dependencies shadow \
    && rm -rf nginx-${NGINX_VERSION} nginx-${NGINX_VERSION}.tar.gz /var/cache/apk/*

# static directory for django
RUN mkdir /static

# volumeの設定
VOLUME /var/cache/nginx

# 設定の書き換え
COPY ./conf/nginx.conf /etc/nginx/nginx.conf
COPY ./conf/uwsgi_params /etc/nginx/uwsgi_params

# 内部で利用するポートの設定
EXPOSE 18082

# 利用するシェルスクリプトをコンテナに配置
COPY ./dockerApp/wakeup.sh /wakeup.sh
COPY ./dockerApp/nginx /etc/init.d/nginx
RUN chmod a+x /wakeup.sh /etc/init.d/nginx

# entrypoint: 何もしない
ENTRYPOINT [""]
# コマンド実行
CMD ["/wakeup.sh"]

また,利用する shell script を以下に示す.

nginx

#!/bin/bash
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="nginx daemon"
NAME=nginx
DAEMON=/usr/local/sbin/${NAME}
SCRIPTNAME=/etc/init.d/${NAME}

# if daemon file not found, exit script.
test -x ${DAEMON} || exit 0

d_start() {
    ${DAEMON} || echo -n " already running"
}

d_stop() {
    ${DAEMON} -s quit || echo -n " not running"
}

d_reload() {
    ${DAEMON} -s reload || echo -n " could not reload"
}

case "$1" in
    start)
        echo -n "Starting ${DESC}: ${NAME}"
        d_start
        sleep 3
        echo "."
        ;;

    stop)
        echo -n "Stopping ${DESC}: ${NAME}"
        d_stop
        sleep 3
        echo "."
        ;;

    reload)
        echo -n "Reloading ${DESC}: configuration..."
        d_reload
        sleep 3
        echo "reloaded."
        ;;

    restart)
        echo -n "Restarting ${DESC}: ${NAME}"
        d_stop
        sleep 5
        d_start
        echo "."
        ;;
    *)
        echo "Usage: ${SCRIPTNAME} {start|stop|restart|reload}" >&2
        exit 3
        ;;
esac

exit 0

wakeup.sh

#!/bin/bash

# Nginx start
/etc/init.d/nginx start

# hook SIGTERM
trap_TERM() {
        echo SIGTERM ACCEPTED.
        exit 0
}
trap 'trap_TERM' TERM

# loop
while :
do
        sleep 5
done

uWSGI の設定ファイル

Nginx で受けたリクエストを Django に投げる際の uWSGI の設定ファイルを以下に示す.

uwsgi_params

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

Nginx の設定ファイル

Nginx のコンフィグファイルを以下に示す.

nginx.conf

# user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    server_names_hash_bucket_size 64;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

default.conf

# the upstream component nginx needs to connect to
upstream call_django {
        ip_hash;
        server django:8081;
}

# configuration of the server
server {
        listen 18082;
        server_name _;
        server_tokens off;
        charset     utf-8;
        access_log  /var/log/nginx/access.log combined;
        error_log   /var/log/nginx/error.log error;

        # max upload size
        client_max_body_size 64M; # adjust to taste

        location /static {
                alias /static;
        }

        # Finally, send all non-media requests to the Django server.
        location / {
                # avoid requests that are neither GET nor POST
                if ( $request_method !~ ^(GET|POST)$ ) {
                        return 444;
                }

                # setting
                include          /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
                uwsgi_pass       call_django;
        }
}

docker-compose の設定(対応箇所の抜粋)

対応する docker-compose の設定情報を以下に示す.今回は,18082 番のポートで待ち受ける.

    nginx:
        # ビルド対象
        build:
            context: ./nginx
            # Dockerfile名
            dockerfile: Dockerfile
        # イメージ名
        image: custom_nginx
        # コンテナ名
        container_name: nginx
        restart: always
        # 環境変数の設定
        environment:
            TZ: Asia/Tokyo
        # ポートの設定(DockerfileのEXPOSEとそろえる)
        ports:
            - "18082:18082"
        # nginxのconfigファイル等の関連付け
        volumes:
            - ./nginx/conf/default.conf:/etc/nginx/conf.d/default.conf:ro
            - ./nginx/cache:/var/cache/nginx
            - ./logs/access.log:/var/log/nginx/access.log
            - ./logs/error.log:/var/log/nginx/error.log
            - ./static:/static:ro
        # 依存関係の記述
        depends_on:
            - django

Docker Image 作成

Docker Image 作成のため,下記を実行する.

docker-compose build

log ファイルの作成

実行ログを記録するための log ファイルを作成する.

touch logs/uwsgi.log logs/access.log logs/error.log

Django のプロジェクトを作成

Django のプロジェクトを作成するため,下記のコマンドを実行する. 参考

# コンテナの作成
docker-compose up -d
# django のコンテナに入る
docker exec -it django bash
# プロジェクトの作成
django-admin startproject membership_system .
# コンテナから抜ける
exit
# 所有者の変更
sudo chown pi:pi -R src/

Django の設定

setting.py の編集

setting.py を修正する.

修正前

ALLOWED_HOSTS = []

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

修正後

ALLOWED_HOSTS = ['localhost']

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

# 修正
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'djangodb',
        'USER': 'postgres',
        'PASSWORD': '1234',
        'HOST': 'db',
        'PORT': 5432,
    }
}

マイグレーションの実行

下記のコマンドを実行する.

docker exec -it django bash
# コンテナ内で作業
./manage.py makemigrations
./manage.py migrate
./manage.py createsuperuser

# いい感じに設定する
#Username (leave blank to use 'root'): admin
#Email address: admin@localhost
#Password:
#Password (again):

# コンテナから抜ける
exit

ページに接続する

ブラウザを開いて下記を入力する.「The install worked successfully! Congratulations!」が表示されれば成功.

http://(ホスト名orIPアドレス):18082

その他設定

タイムゾーンや言語,静的ファイルの設定を行う.

変更前

# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'en_US'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'

変更後

# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'ja-JP'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'
STATIC_ROOT = '/static'
# static フォルダの読み込み専用を取り外す
        volumes:
            - ./src:/code
#            - ./static:/static:ro
            - ./static:/static
            - ./logs/uwsgi.log:/var/log/uwsgi.log
        working_dir: /code
# コンテナの作り直し
docker rm -f $(docker ps -aq)
# コンテナの作成
docker-compose up -d
docker exec -it django bash
# コンテナ内で作業
./manage.py collectstatic
# コンテナから抜ける
exit