docker-compose でWebアプリケーションが動く環境を作る

はじめに

この記事は某所アドベントカレンダー12日目のために書かれた記事です.
100番煎じぐらいのネタですが許して下さい.

環境構築はめんどくさいし時間がかかる

環境構築は人によって好き嫌いの別れる作業だと思いますが,私は嫌いです.
例えばWebアプリケーションを開発するとき,

  • HTTPサーバ(Nginx,Apache等)
  • Webアプリケーションが動く環境(RailsDjango等)
  • サーバとアプリケーションを繋ぐやつ(rack,wsgi等)
  • データベース(MysqlSqlite,Radis等)

この辺のパッケージの導入はほぼ必須になる上,ローカル環境とデプロイ環境で二度構築することになります.
ローカル環境とデプロイ環境が大きく異なる場合,構築手順が大幅に変化しますし, ディストリによってパッケージの更新頻度が異なるので,バージョンのすり合わせなどにも気を使う必要があります.

すごくめんどくないですか?

dockerってなによ

f:id:ekupura:20171211041527p:plain*1

dockerとは,現Docker社が開発を行っている,コンテナ型の仮想化環境を提供するソフトウェアです. 従来型の仮想化ソフトウェア(virtualbox等)とは異なり,ホストOSのカーネルを直に利用している (エミュレーションを行わない)ので非常に軽量であるという特徴があります.
詳しくは公式ページとか読んでください.

docker-composeってなによ

docker-compose は複数のコンテナの構成管理が可能なソフトウェアです.
docker自体には複数のコンテナを管理する機能は含まれていません.そのため,Webアプリケーション開発のような, 複数のコンテナを管理する必要がある場合はdocker-composeを使うと便利です.

docker-composeを使って開発するメリット

一度docker-compose.yml等の設定ファイルを書いてしまえば,そのまま複数の環境で構築を行うことができます. 構築作業もコマンド1〜2行で済むので非常に楽です. また,ローカル環境とデプロイ環境で設定を切り替えたいとき,docker-compose.ymlなどを書き換えるだけで済むため手軽です.

試しにWebアプリケーションを立ち上げてみる

Github

https://github.com/ekupura/docker-compose-test.git

前準備

動かしたい環境にdockerとdocker-composeをインストールする必要があります.
多くのGNU/Linux OSでは標準のパッケージマネージャーで入手可能です.
Windows/Mac OS の場合は公式のページから入手可能です.
BSD系OSは吉報を待ちましょう.

導入する環境

dockerとdocker-composeを使って,以下の構成でwebアプリケーション開発環境を作ってみます.

ディレクトリ構成

以下のような構成でファイルを配置します.(あまり本筋に絡まないファイルは略)

docker-compose.yml
nginx
└ conf.d
  └ myapp.conf
mariadb
├ volume # dbの中身
└ conf.d
  └ mariadb.cnf
django
├ Dockerfile
└ myapp
  ├ myapp
  │  └ settings.py
  └ uwsgi_params

docker-compose.yml

大本の設定ファイルです.yaml記法で各コンテナごとに設定を書いていきます. 各オプションの詳しい効用は公式ドキュメントを参照して下さい.

version: '2'
services:
    mariadb:
        image: mariadb:latest
        container_name: mariadb
        volumes:
            - ./mariadb/volume:/var/lib/mysql
            - ./mariadb/conf.d:/etc/mysql/conf.d
        environment:
            - MYSQL_ROOT_PASSWORD=root

    django:
        build: ./django
        container_name: django
        volumes:
            - ./django/myapp:/usr/src/app
        working_dir: /usr/src/app
        ports:
            - "8001:8001"
        links:
            - mariadb:mysql
        command: "uwsgi --socket :8001 --module myapp.wsgi"

    nginx:
        image: nginx:latest
        container_name: nginx
        volumes:
            - ./nginx/conf.d:/etc/nginx/conf.d/
        volumes_from:
            - django
        links:
            - django
        ports:
            - "80:80"
            - "443:443"

mariadb,nginxはDockerHub上のofficialイメージをそのまま使用します.
また,django & uwgsi はpythonのofficialイメージを独自に改良して使う必要があるため,Dockerfileを作成します.

django/Dockerfile
FROM python:latest
RUN apt update
RUN apt install -y git mariadb-client
RUN pip3 install mysqlclient
RUN pip3 install uwsgi django-jquery django-static-jquery

設定

各コンテナの設定は各ディレクトリのconf.d以下にファイルを作成することで行います.

nginx/conf.d/myapp.conf
upstream django {
    server django:8001;
}

server {
    listen 80;
    listen [::]:80;
    server_name [your_server_name];
    charset utf-8;

    location / {
        uwsgi_pass django;
        include /usr/src/app/uwsgi_params;
    }

    location /static {
        alias /usr/src/app/static;
    }
}
mariadb/conf.d/mariadb.cnf
# MariaDB-specific config file.
# Read by /etc/mysql/my.cnf

[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
default-character-set = utf8mb4

[mysqld]
#
# * Character sets
# 
# Default is Latin1, if you need UTF-8 set all this (also in client section)
#
character-set-server  = utf8mb4 
collation-server      = utf8mb4_general_ci 
character_set_server   = utf8mb4 
collation_server       = utf8mb4_general_ci 
# Import all .cnf files from configuration directory
!includedir /etc/mysql/mariadb.conf.d/

アプリケーションの準備

公式のチュートリアルに従って,簡単なレスポンスを返すDjangoアプリケーションを作成します.
(モデル周りはめんどくさくなったのでやりません)
デフォルトではSQLiteを使用するようになっているので,mariadbを使うためにsettings.pyのDATABASES部分を以下のように書き換えます.

django/myapp/myapp/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '[your_db_name]',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': 'mariadb',
        'PORT': '3306'
    }
}

また,以下のようなファイルを作成します.

django/myapp/uwgsi_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;

実際に動かす

docker-compose build # イメージの構築
docker-compose up -d   # コンテナの立ち上げ

確認

curl -XGET http://[your_server_name]/polls

まともそうなレスポンスが返ってくればきっと動いてます.

まとめ

設定ファイルの書き方に若干癖がありますが,慣れてしまえば簡単に書けるようになります.
dockerとdocker-composeを使いこなして快適に開発しましょう.