新着記事

Viewing posts for the category Docker

PHPをnginx+FPMの環境で動作させる

古いPHPのWebアプリの改修を行うことになりました。
まずはメンテナンス性の確保のためにオレオレフレームワークからLaravelに載せ替える。
また、1台サーバーを使用して動かしていたが、あまり大きなアプリではないので、kubernetesで動作させることにします。
そして合わせて将来的な技術投資としてWebサーバーをApacheからnginx + FastCGI Process Manager(FPM)を試してみることにしました。
その際のdokcerとkubernetesの設定の備忘録になります。

nginxのconfファイルの作成

まずはLaravelとphp-fpm用にしたnginxのconfファイルを作成。
default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  example.com;

    access_log  /var/log/nginx/host.access.log;
    error_log  /var/log/nginx/host.error.log;

    location / {
        root   /usr/share/nginx/html;
        index  index.php index.html index.htm;
        # リクエストされたファイルが存在しなければ、Laravelのフロントコントローラーに内部リダイレクトさせる
        try_files $uri /index.php?$query_string;
    }

    # 400番台のエラーページの設定
    error_page  404              /404.html;

    # 500番台のエラーページの設定
    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # Apacheの設定なので今回はコメントアウトのまま
    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # FastCGIの設定
    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        # Laravelのルートディレクトリ
        root           /var/www/html/public;
        # nginxからphp-fpmに受け渡すIPアドレスとポート番号の設定
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        # 全てのリクエストをLaravelのフロントコントローラーで実行させる
        fastcgi_param  SCRIPT_FILENAME  $document_root/index.php;
        include        fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
ここでの注意点はnginxからphp-fpmに受け渡すIPアドレスとポート番号の設定
ローカル環境で動作させる場合はdokcerのphp-fpmのコンテナを指定してください。
fastcgi_pass   php-fpm:9000;
kubernetesで動作させる場合は1pod内でnginxのコンテナとphp-fpmのコンテナを動作させるため127.0.0.1:9000で受け取ることができます

nginxのDockerfileの作成

Docker Hubから最新のものを使用。
Dockerfile
FROM nginx:1.23.3

COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80 443

STOPSIGNAL SIGQUIT

CMD ["nginx", "-g", "daemon off;"]

php-fpmのDockerfileの作成

こちらもDocker Hubから最新のものを使用。
注意点はnginxがアクセスできるようにLaravelのプロジェクトを配置しているディレクトリの所有ユーザーを変更すること。
アクセスしてくるのはnginxなので所有ユーザーをwww-dataに変更しておかないと404エラーになります。
Dockerfile
FROM php:8.1.16-fpm

#PHPの拡張機能のインストール
RUN apt update \
    && apt install -y libonig-dev libxml2-dev libcurl4-openssl-dev libssl-dev libzip-dev \
    && docker-php-ext-install pdo pdo_mysql mysqli simplexml curl phar zip ftp \
    && pecl install xdebug redis \
    && docker-php-ext-enable xdebug redis

# nginxがアクセスできるように所有ユーザーを変更
COPY project /var/www/html
RUN chown -R www-data:www-data /var/www/html

EXPOSE 9000

ENTRYPOINT ["docker-php-entrypoint"]

CMD ["php-fpm"]

kubernetesの設定の作成

kubernetesに反映させるdeployment、service、ingressを作成します。
deployment.yaml
1pod内で動作させるためcontainersにnginxとphp-fpmのコンテナを記載します。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
  labels:
    app: example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      containers:
        - image: php-fpm:latest
          name: example-php-fpm
          ports:
            - containerPort: 9000
              protocol: TCP
        - image: nginx:latest
          name: example-nginx
          ports:
            - containerPort: 80
              protocol: TCP
service.yaml
外からのアクセスはnginxが受けるのでポートは80番。
kind: Service
apiVersion: v1
metadata:
  name: example-service
spec:
  type: NodePort
  selector:
    app: example
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: example-service
                port:
                  number: 80

kubernetesに反映を実行。 これで動作できました。

旧Redash(V2) から 新Redash(V8) にアップデートを行いました

Qiita の TORICO Advent Calendar 2019 の記事として書きました

社内での実績閲覧のツールとして Re:dash を使っています。

最初に導入した Re:dash v2 のまましばらくアップデートを行っていなかったので、v8 にアップデートを行いました。

アップデート方針

v8 は dockerコンテナで提供され、 docker-compose で起動させることができます。提供されている docker-compose.yml は、Postgres や redis コンテナの起動も自動でされますし、インストールスクリプトも良くできており、初期状態の ubuntu サーバであればコマンド一発で docker エンジンのインストールも含めアプリの起動まで行うことができます。

従来の EC2イメージの Redash から、スクリプトでアップデートできたら楽なのですが、少し試したところ Postgres の DB のスキーマ名が変わっていたり、Postgresのサーバのバージョンも 9.3 -> 9.6 への大きなアップデートとなることもあり、今回は「Redash v8 を新規EC2で起動し、旧サーバからDBのレコードをコピーする」という方針としました。

Redash V8 サーバの構築

https://github.com/getredash/setup/ こちらのスクリプトを使うことで、非常に簡単に起動させることができます。

1. EC2 で Ubuntu18 サーバを起動

2. ホームディレクトリで、

git clone git@github.com:getredash/setup.git

3.

cd setup
bash setup.sh

あとは、スクリプトの中で docker エンジンのインストール、postgres のデータファイル構築や ランダムなDBパスワードの作成、初期スキーマの構築などすべて行ってくれます。スクリプト終了時に docker-compose up -d まで行うため、ブラウザでアクセスすれば Redash のサインインページが表示されます。

postgres コンテナへの接続

インポートするために、Postgres の Docker コンテナに外部から接続できるようにします。

上記スクリプトで Redash をインストールした場合、/opt/redash/docker-compose.yml が作成されますので、この postgres サービスの箇所に

 postgres:
image: postgres:9.6-alpine
env_file: /opt/redash/env
volumes:
- /opt/redash/postgres-data:/var/lib/postgresql/data
restart: always
# 追加
ports:
- "5432:5432"

ports項目を追加し、ホストマシンの5432ポートをコンテナに接続します。
/opt/redash/env の POSTGRES_PASSWORD に作成されているパスワードと、ユーザー名 postgres でコンテナの postgres に接続できます。

旧サーバの暗号キー等の設定のコピー

旧サーバの、/opt/redash/.env の設定値を新サーバにコピーします。

REDASH_COOKIE_SECRET 

REDASH_COOKIE_SECRET は、DBの data_sources テーブルにある暗号化フィールドの復号化に使われますので、テーブル内容をそのままコピーする場合は一致させる必要があります。

これを一致させない場合、Redash 起動時の data source の選択の際にローディングスピナーがぐるぐる回り続けることになります。APIレスポンス自体はHTTP500が返ってきており、docker-compose のログには Pythonの例外が、暗号化内容を復号できない旨のメッセージと共に出力されます。肝心のトレースバック(スタックトレース)は保存し忘れました。

実際のDBの復号化には settings.DATASOURCE_SECRET_KEY が暗号キーとして使われ、settingsを読んでみると

COOKIE_SECRET = os.environ.get("REDASH_COOKIE_SECRET", "c292a0a3aa32397cdb050e233733900f")
SECRET_KEY = os.environ.get('REDASH_SECRET_KEY', COOKIE_SECRET)
DATASOURCE_SECRET_KEY = os.environ.get('REDASH_SECRET_KEY', SECRET_KEY)

このようになっており、DBの暗号キーとクッキーの暗号キーは個別に設定できるようですが、旧Redashの場合はそれぞれ同じ値を使っていると思いますので、新サーバの /opt/redash/env には 旧サーバの /opt/redash/.env から REDASH_COOKIE_SECRET の内容だけコピーしておきます。REDASH_SECRET_KEY ができていたら項目ごと消しておきます。

その他の設定

Google (Gsuite ) を使っている場合は、

REDASH_GOOGLE_APPS_DOMAIN
REDASH_GOOGLE_CLIENT_ID
REDASH_GOOGLE_CLIENT_SECRET

をコピーすることで新サーバでもGoogle 認証が行えるようになります。そのほか、REDASH_MAIL_* など、旧サーバの設定内容はそのままコピーします。

REDASH_GOOGLE_CLIENT_ID="1xxxxxxxx.apps.googleusercontent.com"

このように、ダブルクォーテーションで囲っているとV8ではうまく動作しませんので、envファイル内でダブルクオーテーションは書かないようにします。

テーブル内容のコピー

おそらく、慣れてる方であれば pg_dump を使うのが良いと思うのですが、私は postgres や pg_dump の経験があまり無いため、datagrip を使ってSELECT 結果から INSERT 文を生成し、それをコピペで流し込むことにしました。

旧Redash からの変更点として、データベーススキーマ名が redash から postgres に変更されたこと、また旧版の queries テーブルや dashboards にあった user_email フィールドが無くなっていることなどあり、pg_dump での対応が難しそうだと思ったためです。

データ量として 700クエリー、30ダッシュボード、60ユーザー程度の規模ですので、コピペで十分対応できました。なお、query_results テーブルに過去のSQL結果が入ってますが、2GB程度のストレージを使っており、不要だと思ったため今回は query_results は移行しませんでした。

旧サーバの postgres に接続し、以下のテーブル内容をコピーしていきます。

organizations
users
data_sources
groups
data_source_groups
queries
visualizations
dashboards
widgets

外部キー制約があるため、流し込む順番が違うと失敗しますが、上記の順番で INSERT できると思います。

queries , dashboards には user_email という不要フィールドがあり、queries にはさらに query_results への参照があるのですが、それらは不要なため下記のようなSELECT 文で datagrip 上で検索し、INSERT 文としてコピーして 新DBに INSERT します。

SELECT id, updated_at, created_at, org_id, data_source_id, name, description, query, query_hash, api_key, user_id, last_modified_by_id, is_archived, options, version, is_draft, schedule_failures, search_vector, tags, schedule
FROM public.queries
ORDER BY id;
SELECT id, updated_at, created_at, org_id, slug, name, user_id, layout, dashboard_filters_enabled, is_archived, version, is_draft, tags
FROM public.dashboards
ORDER BY id;

ついでに、MySQL データソースは RDS用のものが新たに出来ていたため、 data_sources の type フィールドは mysql から rds_mysql 変更しました。

シーケンスの更新

INSERT しただけではオートインクリメントPKに使われるシーケンス番号が1から始まり、新しいクエリを保存する時エラーになってしまうので、シーケンスも更新しておきます。

SELECT * FROM users_id_seq;
SELECT MAX(id) + 1 FROM users;
ALTER SEQUENCE users_id_seq RESTART WITH 61;

SELECT * FROM groups_id_seq;
SELECT MAX(id) + 1 FROM groups;
ALTER SEQUENCE groups_id_seq RESTART WITH 6;

SELECT * FROM data_sources_id_seq;
SELECT MAX(id) + 1 FROM data_sources;
ALTER SEQUENCE data_sources_id_seq RESTART WITH 24;

SELECT * FROM data_source_groups_id_seq;
SELECT MAX(id) + 1 FROM data_source_groups;
ALTER SEQUENCE data_source_groups_id_seq RESTART WITH 22;

SELECT * FROM dashboards_id_seq;
SELECT MAX(id) + 1 FROM dashboards;
ALTER SEQUENCE dashboards_id_seq RESTART WITH 37;

SELECT * FROM queries_id_seq;
SELECT MAX(id) + 1 FROM queries;
ALTER SEQUENCE queries_id_seq RESTART WITH 699;

SELECT * FROM visualizations_id_seq;
SELECT MAX(id) + 1 FROM visualizations;
ALTER SEQUENCE visualizations_id_seq RESTART WITH 1230;

SELECT * FROM widgets_id_seq;
SELECT MAX(id) + 1 FROM widgets;
ALTER SEQUENCE widgets_id_seq RESTART WITH 695;

このように、MAX(id) の結果をコピペしてALTER SEQUENCE していきました。1行で書けそうなのですが、経験が無く書き方がわからなかったため、愚直に書いてます。

これで、新サーバで旧サーバの状態が再現されていると思います。

nginx に SSL証明書を組み込む

自己認証局のSSL証明書がありますので、使います。

参考: dockerでredashのnginxをssl化したら思いの外ハマった

mkdir -p /home/ubuntu/nginx/certs

certs に、証明書 ( my-awesome.crt, my-awesome.key )を入れる 

/home/ubuntu/nginx/default.conf を作成

upstream redash {
server redash:5000;
}

server {
listen 80 default;
return 301 https://$host$request_uri;
}

server {
listen 443;
ssl on;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2;
ssl_ciphers "ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!EXPORT:!DES:!3DES:!MD5:!DSS";

gzip on;
gzip_types *;
gzip_proxied any;

ssl_certificate /etc/nginx/certs/my-awesome.crt;
ssl_certificate_key /etc/nginx/certs/my-awesome.key;

error_log /var/log/nginx/nginx_error.log;
access_log /var/log/nginx/nginx_access.log;

location / {
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_pass http://redash;
}
}

/opt/redash/docker-compose.yml を修正

 nginx:
image: redash/nginx:latest
ports:
- "80:80"
- "443:443"
depends_on:
- server
links:
- server:redash
restart: always
volumes:
- /home/ubuntu/nginx/default.conf:/etc/nginx/conf.d/default.conf
- /home/ubuntu/nginx/certs:/etc/nginx/certs

最後に

繰り返しとなりますが、データソース選択ビューで、INSERTしたはずのデータソースが表示されず、ぐるぐるとローディングスピナーが回り続ける場合、旧サーバと settings.DATASOURCE_SECRET_KEY が一致していません。/opt/redash/env の REDASH_COOKIE_SECRET を旧サーバと同じにして、REDASH_SECRET_KEY 設定を消すとデータソースが見れるようになると思います。

PyCharm + Docker で Django 開発環境を構築する

PyCharm 2016 の Docker サポートの使い勝手が良いです。

Docker で開発環境を作るのは初めてだったのですが、

  • ローカル ( mac ) は Docker Toolbox を使って開発環境を作る。PyCharm のデバッガでステップ実行できるようにする。
  • ソースコード、およびログディレクトリは Docker イメージの中に入れず、ホストのディレクトリをマウントして使う
  • 公開サーバを見越して uwsgi, nginx の設定も作っておく


という所までできたので、手順を書きます。

コード置いてあります。 https://github.com/ytyng/docker-django-skeleton

こちらを参考にしました。https://github.com/dockerfiles/django-uwsgi-nginx

必要アプリのインストール

インストーラに従ってインストールしておきます。

プロジェクトディレクトリを作成し、PyCharm で開く

$ mkdir docker-django-skeleton

$ open -a PyCharm docker-django-skeleton

PyCharm用の Bash プラグインのインストール

メニューバーの PyCharm → Preferences → 検索: Plugins → Plugins の検索で「BashSupport」を検索 → 該当したものをインストールしておきます。

PyCharmの再起動を求められるので、案内通り再起動します。

Docker 用のファイルを作る

プロジェクトルートに Dockerfile そのまま置くと煩雑になってしまうので、docker ディレクトリを作って関連ファイルを入れます。

docker/Dockerfile

FROM ubuntu:16.04

MAINTAINER ytyng

RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    python3-dev \
    python3-setuptools \
    libjpeg-dev \
    nginx \
    supervisor \
  && rm -rf /var/lib/apt/lists/*

# ipython, gnureadline が必要なら
# lib32ncurses5-dev

RUN ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/libjpeg.so

# RUN easy_install3 pip  # aptで入れた方が安定

COPY requirements/base.txt /tmp/requirements/base.txt
RUN pip3 install -r /tmp/requirements/base.txt

# setup all the configfiles
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
COPY nginx-app.conf /etc/nginx/sites-available/default
COPY supervisor-app.conf /etc/supervisor/conf.d/

RUN mkdir -p /etc/nginx/certs
# COPY certs /etc/nginx/certs/

RUN mkdir -p /var/run/django/

# set locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

EXPOSE 80
#EXPOSE 443

↑ libjpeg などインストールしてるのは Pillow 用

docker/requirements/base.txt

Django==1.10.1
pytz
uwsgi
# MySQL使う場合
PyMySQL

↑ 今回のサンプルは、DBは SQLite3 なので PyMySQL 不要ですがサンプルとして書いてます。



docker/nginx-app.conf

server {
    listen 80;
    # listen 443 ssl;

    server_name docker-django-skeleton.example.com;

    charset utf-8;

    # ssl_certificate /etc/nginx/certs/xxx.crt;
    # ssl_certificate_key /etc/nginx/certs/xxx.key;

    location /static/ {
        alias /var/django/docker-django-skeleton/staticfiles/;
        break;
    }

    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:3031;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

docker/supervisor-app.conf

[program:app-uwsgi]
command = /usr/local/bin/uwsgi --ini /var/django/docker-django-skeleton/conf/uwsgi.ini

[program:nginx-app]
command = /usr/sbin/nginx

Docker 用の設定ファイルの作成

環境変数など設定する Bash スクリプトを用意しておきます。
mac で実行した場合と公開サーバで起動した場合に読み込まれる設定を変えるようにしています。

docker/_settings.sh

#!/usr/bin/env bash

APP_NAME=docker-django-skeleton
DJANGO_APP_NAME=docker_django_skeleton

PROJECT_DIR=$(cd $(dirname ${BASH_SOURCE:-$0})/..;pwd)

if [ $(which docker-machine) ]; then
    # mac
    eval "$(docker-machine env default)"
    DOCKER_COMMAND=docker
    DOCKER_MACHINE_COMMAND=docker-machine
    LOG_DIR=/tmp/log/${APP_NAME}
    export UWSGI_PROCESSES=1
    export UWSGI_THREADS=1
    export DJANGO_SETTINGS_MODULE=${DJANGO_APP_NAME}.settings.local
else
    # ubuntu
    DOCKER_COMMAND="sudo docker"
    LOG_DIR=/var/log/${APP_NAME}
    OPTIONAL_PARAMS="--link mysql:mysql"
    RUN_COMMAND="supervisord -n"
    export UWSGI_PROCESSES=2
    export UWSGI_THREADS=2
    export DJANGO_SETTINGS_MODULE=${DJANGO_APP_NAME}.settings.production
fi


Dockerイメージ作成用スクリプト

docker/docker-01-build.sh

#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh

${DOCKER_COMMAND} build -t ${APP_NAME} .

docker/docker-02-run.sh

#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh

mkdir -p -m 777 ${LOG_DIR}

${DOCKER_COMMAND} run -d -P -p 80:80 -p 443:443 \
  -v ${PROJECT_DIR}:/var/django/${APP_NAME} \
  -v ${LOG_DIR}:/var/log/django \
  -v /etc/localtime:/etc/localtime:ro \
  -e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
  -e UWSGI_PROCESSES=${UWSGI_PROCESSES} \
  -e UWSGI_THREADS=${UWSGI_THREADS} \
  ${OPTIONAL_PARAMS} \
  --name ${APP_NAME} ${APP_NAME} ${RUN_COMMAND}

if [ "${DOCKER_MACHINE_COMMAND}" ]; then
    docker-machine ip default
fi

${DOCKER_COMMAND} ps

docker/docker-03-bash.sh

#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh

EXISTS=$(${DOCKER_COMMAND} ps --quiet --filter name=${APP_NAME})

if [ "${EXISTS}" ]; then
    ${DOCKER_COMMAND} exec -it ${APP_NAME} /bin/bash $@
else
    ${DOCKER_COMMAND} run --rm -it \
    -e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
    -v ${PROJECT_DIR}:/var/django/${APP_NAME} \
    --name ${APP_NAME} ${APP_NAME} /bin/bash $@
fi

docker/docker-09-rm.sh

#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh

${DOCKER_COMMAND} rm --force ${APP_NAME}

docker/manage.sh

#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh

EXISTS=$(${DOCKER_COMMAND} ps --quiet --filter name=${APP_NAME})

if [ "${EXISTS}" ]; then
    ${DOCKER_COMMAND} exec -it ${APP_NAME} \
    /bin/bash -c "cd /var/django/${APP_NAME}/${APP_NAME}/; ./manage.py $*"

else
    ${DOCKER_COMMAND} run --rm -it \
    -e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
    -v ${PROJECT_DIR}:/var/django/${APP_NAME} \
    --name ${APP_NAME} ${APP_NAME} /bin/bash -c \
    "cd /var/django/${APP_NAME}/${APP_NAME}/; ./manage.py $*"
fi


*.sh には、実行パーミッションを付与しておきます。

$ chmod +x docker-*.sh manage.sh

docker-django-skeleton
└── docker
    ├── Dockerfile
    ├── _settings.sh
    ├── docker-01-build.sh
    ├── docker-02-run.sh
    ├── docker-03-bash.sh
    ├── docker-09-rm.sh
    ├── manage.sh
    ├── nginx-app.conf
    ├── requirements
    │   └── base.txt
    └── supervisor-app.conf


Docker イメージの作成

先ほど作成した、docker-01-build.sh を PyCharm 上で右クリック → Run 'docker-01-build.sh'


Dockerイメージができます。

Django プロジェクトディレクトリの作成

既に他の件で Django が mac にインストールされている場合は、それを使って `django-admin.py startproject` すれば良いと思いますが、今回は先ほど Docker イメージにインストールした Django を使って Django プロジェクトを作成します。

プロジェクトディレクトリをまるごと Docker にマウントし、Docker内で startproject します。

$ docker run -it -v `pwd`:/var/django/docker-django-skeleton docker-django-skeleton /bin/bash

※ pwd は、docker-django-skeleton ディレクトリ。docker ディレクトリの親ディレクトリ

$ docker run -it -v `pwd`:/var/django/docker-django-skeleton docker-django-skeleton /bin/bash
root@8d2ba7a54287:/# cd /var/django/docker-django-skeleton/
root@8d2ba7a54287:/var/django/docker-django-skeleton# django-admin.py startproject docker_django_skeleton
root@8d2ba7a54287:/var/django/docker-django-skeleton# mv docker_django_skeleton docker-django-skeleton
root@8d2ba7a54287:/var/django/docker-django-skeleton#


好みの問題ですが、Django プロジェクトのディレクトリ名は アンダーバーではなく ハイフンに変更しています。

PyCharm を見てみると、docker-django-skeleton ディレクトリが作成されているのが確認できます。

settings を環境ごとに分ける

Django でよくやるプラクティスで、settings を ローカル環境と公開環境で分けるというものがあります。

docker_django_skeleton ディレクトリ内で、

1. settings ディレクトリを作成
2. settings.py は、 settings/base.py に改名
3. settings/local.py settings/production.py を作成。


settings/local.py, settings/production.py の内容は以下のようになります。

settings/local.py

from .base import *  # NOQA


内容はありませんが、今回はこれで良しとします。

manage.py のインタプリタ (シェバン shebang ) を python3 にしておく


作成された manage.py を見てみると、1行目が

manage.py

#!/usr/bin/env python

となっていますが、Docker イメージ内には Python2 が残っているため不具合が起こることがあります。

#!/usr/bin/env python3

に変更しておきます。

PyCharm のインタプリタで Docker の Python を指定する

PyCharm → Preferences → 検索: interpreter

Project Interpreter が出てきます。

ここで、右上の「...」ボタンをクリックし、Add Remote を選択。

Configure Remote Python Interpreter になるので、
「Docker」を選択、Image name は docker-django-skeleton:latest を選択してください。

それと、Python interpreter path: は python となっていますが、python3 に変更します。

すると、Docker 内の Python 環境を認識します。すごい!

Djangoサポートを有効にする

Preferences で、検索: django

Language & Frameworks の Django が出て来るので選択し、Enable Django Support にチェック。

Django project root: manage.py のある、docker-django-skeleton
Settings: docker_django_skeleton/settings/local.py

OKをクリック

Project Structure を設定する

Preferences で、検索: structure

manage.py のある、docker-django-skeleton ディレクトリを選択し、Source をクリック → OK

migrate

次は、./manage.py migrate をします。
docker コンテナ内なので、./manage.py を実行するのも少し面倒ですが、docker ディレクトリの中に manage.sh を作ってあるのでこれを使います。

$ cd docker
$ ./manage.sh

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

[django]
    check
    compilemessages
...

$ ./manage.sh migrate
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
...

Docker の Django環境を使ってマイグレーションしてくれました。

テストサーバの起動

PyCharm の右上、Run/Debug の選択をクリックし、Edit Configurations...

Run/Debug Configurations ダイアログで、左上の + をクリック

Django server を選択

Host: には、0.0.0.0 を入力(重要)
Name: は適当に (例: runserver )
→ OK

出来た runserver 実行環境が選択されている状態で、虫(デバッグ) ボタンを押下

System check identified no issues (0 silenced).
September 26, 2016 - 09:54:15
Django version 1.10.1, using settings 'docker_django_skeleton.settings.local'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

となりますので、0.0.0.0:8000 をクリックするとブラウザが起動し、Docker マシーンにリダイレクトされてページが表示されます。
デバッガも有効な状態ですので、ブレイクポイントが使えます。すごい!

公開環境で起動する

uwsgi.ini

[uwsgi]

app = $(APP_NAME)
django_app = $(DJANGO_APP_NAME)

base = /var/django/%(app)/%(app)/
pythonpath = %(base)
chdir = %(base)

socket = 127.0.0.1:3031

module = %(django_app).wsgi:application

processes = $(UWSGI_PROCESSES)
threads = $(UWSGI_THREADS)

master = true

pidfile = /var/run/django/%(app).pid

touch-reload = %(base)/%(django_app)/wsgi.py
lazy-apps = true
thunder-lock = true

buffer-size = 32768

logto = /var/log/django/%(app)/%n.log

uwsgi の設定ファイルはこんな感じですかね。

ソースコードを公開環境のサーバに持っていって、

$ ./docker-01-build.sh

でコンテナを作り (ローカルで作ったのを Docker hub に push -> 本番で Pull でもいいですが)、

$ docker-02-run.sh

で起動すると、公開環境 (というか docker-machine がインストールされてない環境 ) では本番用設定で nginx → uwsgi → Django で起動します。

Docker コンテナを削除する時は

$ docker-09-rm.sh

で消えます。

Search