この記事は、Makuake Development Team Advent Calendar 2019 7日めの記事です。
yutakiと申します。
PRIME ORDERというWebシステム開発サービスのエンジニアリングマネージャをやっております。
https://prime-order.jp/
概要
最近、レガシーな案件のプレビューのために
十数年ずっと頑張ってきたオンプレの共有開発サーバが故障してしまい
急いでnginx-proxyとdocker-composeで複数案件の開発環境を復活させた話をします。
やったこと(ざっくり)
※端末はmacです
基本的に下記のコンテナ構成でプロジェクトを作成
- 新しめ(laravel系): [nginx] + [php] + [mysql] + [node(build専用)] の4台構成
- 古め(その他): [apache & php] + [mysql] の2台構成
そしてnginx-proxyでローカルドメインを割り当てました。
たとえばhogeプロジェクトであれば http://hoge.localhost
で使えるようにした感じです。
1. 案件ごとの構成をdocker-composeで作成
ベースimageの選定について
一般的な構成の時は、app以外はほぼ公式イメージで対応しました。
appについては、docker-php-ext-installを使えるので、エクステンションの管理も楽です。
一部、pecl経由でないと入れられないものもありますがそれはpeclで入れて有効にすればいいだけ。
(imagemagickとか)
FROM php:7.1-fpm-alpine
# lib
RUN apk add --no-cache --virtual build-dependencies gcc make autoconf libc-dev libtool \
&& apk add --no-cache --virtual zlib1g-dev libxml2-dev \
&& apk add --no-cache --virtual libmagickwand-dev libpng-dev imagemagick-dev
# composer
COPY --from=composer /usr/bin/composer /usr/bin/composer
# php extension
RUN docker-php-ext-install zip xml pdo_mysql gd
RUN pecl install imagick \
&& docker-php-ext-enable imagick
RUN pecl install mailparse \
&& docker-php-ext-enable mailparse
COPY php.ini /usr/local/etc/php/
WORKDIR /var/www
こんな感じで書いたものを使いまわしていけました。
apacheが一緒になっている5.4系のイメージなどはこんな感じ。
FROM php:5.4.45-apache
# composer
COPY --from=composer /usr/bin/composer /usr/bin/composer
# lib
RUN apt-get update \
&& apt-get install -y git libmagickwand-dev libmcrypt-dev
# php extension
RUN docker-php-ext-install mcrypt pdo pdo_mysql zip \
&& pecl install imagick \
&& docker-php-ext-enable imagick
# apache module
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/ \
&& mv /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/
# conf, ini
COPY site.conf /etc/apache2/sites-enabled/site.conf
COPY php.ini /usr/local/etc/php/php.ini
WORKDIR /var/www/site
apacheのモジュールがconfファイルを移動するだけで有効になるので楽なのがポイントです。
あとは、ごく少数、PHP5.2みたいな古いバージョンが使われている社内システムもありました。
そちらは公式にはバージョンがないので、DockerHubで該当バージョンを使っているものを探して利用しました。
例えば下記など。
https://github.com/andres-ortiz/php5.2-apache2.2
セキュリティパッチ等当ててくれているので開発環境とはいえありがたいです。
ただこのimageは起動時にrun.shでhtdocs以下にログディレクトリを作成してしまうので
スクリプトを上書きするかDocumentrootを変更するなどすると良いと思います。
2. nginx-proxy
こちらを利用します。
https://github.com/jwilder/nginx-proxy
使い方の要点は下記です。
- どこでもいいのでnginx-proxyをdocker-compose.yml経由で起動しておく
- 各案件のdocker-composeの調整
- 「VIRTUAL_HOST」という環境変数でホスト名を定義する
- nginx-proxyと同じネットワークに所属させる
nginx-proxyを起動しっぱなしにしておけば特に他に設定が不要という神ツールです。
(dockerのプロセスを監視、各docker-composeのup、downを検知して勝手にプロキシしてくれます)
nginx-proxy本体のdocker-compose.yml
docker-compose.ymlは最小構成ならこれだけ
version: '2'
services:
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
restart: always
ちなみにネットワーク名は固定してもいいと思います。
nginx-proxyというディレクトリで起動しているなら「nginx-proxy_default」
がネットワーク名になります。
各案件のdocker-compose.yml
たとえばこう
version: '3'
services:
hoge-web-php:
image: ${WEB_PHP_IMAGE}
build: docker/web-php
ports:
- 80
volumes:
- ./logs/apache2:/usr/local/apache2/logs:cached
- ./server:/usr/local/apache2/app:cached
environment:
VIRTUAL_HOST: hoge.localhost
hoge-db:
image: ${MYSQL_IMAGE}
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DBNAME}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: ${MYSQL_TZ}
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- ./logs/mysql:/var/log/mysql:cached
- ./docker/db/data:/var/lib/mysql:cached
- ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/db/sql:/docker-entrypoint-initdb.d
ports:
- 3306
# 下記はnginx-proxyを利用するときのみ解放
networks:
default:
external:
name: nginx-proxy_default
webサーバのコンテナのポートは80番にしてください。
あと、サービス名(hoge-web-php, hoge-dbなど)はネットワーク内でuniqueである必要があります。
案件名をprefixなどでつけておくといいと思います。
ポイントは、hoge-web-phpの
environment:
VIRTUAL_HOST=hoge.localost
そして最下部の
networks:
default:
external:
name: nginx-proxy_default
です。
なお、このnetworksセクションをコメントアウトしてしまえば通常通りポートフォワードでの利用もできます。
nginx-proxyにproxyさせたいときだけ記述すれば良いです。
これで、http://hoge.localhost
で該当案件を処理することができます。
その他
proxyの設定をいじりたい場合
confを上書きすれば簡単です。
こんなふうに上書き
volumes:
- ./proxy.conf:/etc/nginx/proxy.conf
デフォルトの中身はこうです。
(必要なものは揃っている印象です)
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";
SSL対応(リンク紹介だけ)
nginx-proxyをssl対応する場合は
https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion
を活用すれば死ぬほど簡単に対応できます。
双方の活用は、素晴らしい参考記事がありましたので貼っておきます
https://tech.quartetcom.co.jp/2017/04/11/multiple-ssl-apps-on-one-docker-host/
Laravel Valetを利用する場合
80/443ポートの食い合いになるので使う時はvalet stop
してください。
Laravel Valetはローカルにnginxを立ち上げていて、dnsmasqと併用して似たようなことをしています。
valetと共存させようと欲張り、nginx-proxyのポートを8080:80
にして運用しようとしてみたところ、プロキシはされるのですが
ローカル -> nginxの間のX-Forwarded-*系を伝搬させることができず
Laravelのrouteメソッドなどで適切なURLが作成できませんでした。
しばらく調べてみたんですが、案件ごとにごちゃごちゃ設定するしか手がなさそうだったので断念。
これTCPのプロキシならMySQLもいけるんじゃ?->いけなかった
MySQLも3306:3306
でプロキシしてhoge-db.localhost
でSequel Proとかでアクセスできるんじゃないのか?
と思ってやってみましたが、ホストは解決できるものの正常に通信はできませんでした。
超残念。こちらは大人しくサービスごとにport設定するなどしています。
issueでも似たこと話してました。
https://github.com/jwilder/nginx-proxy/issues/318