こんにちは
タイトルの通りに今日はDockerでlaravelの本番環境構築経験を述べたいと思います。
私はまだ日本語を勉強中なので。わかりにくいことがあれば申し訳ありません。
よろしくお願いします。
前回は開発環境について話しました。下記です。
http://qiita.com/mytv1/items/f26cd77f2801357dee8f
今回の本番構築は前回に述べた開発環境構築と違うところがいくらかあります。主にはサービス管理仕方とサービスをビルドイメージについてです。
詳細は下記にお書きします。
本番環境
下記は自分の本番環境情報です:
-
ソフトウェア:
OS : Alpine Linux 3.5.2
Docker-Client : 17.06.0-ce
Docker-Server: 17.06.0-ce
docker-compose : 1.15.0 -
ハードウェア:
awsのサービスを使います。t2.mircoの3つのインスタントです。
今度はdocker swarm
を使うということで、上の3つインスタントを一つの管理ノードと2つのワーカーノードに割り当てる予定です。
予定の環境構築
- docker swarm モードで走ります。
- 下記のサービスを上げます:
- app : laravelの処理を行うサービス
- web : nginxを持つサービス
- database : データベース管理サービス
- redis : redisサービス
ブラウザーの確認でデフォルトの「Laravel」が表示できると ok だという認識ですすめました。
まずはプロジェクトのディレクトリの構造について話したいと思います。
1. ディレクトリ構造
projectname/
www/
/* laravel source code */
conf/
web/
prod.vhost.conf
dev.vhost.conf
prod.web.dockerfile
prod.app.dockerfile
prod.docker-compose.yml
dev.web.dockerfile
dev.app.dockerfile
dev.docker-compose.yml
インターネット上で参考が見つからないので、構造は自分で考えて上記でしてみました。
-
www
: laravelのマインのソースコードを置きる場所。 -
conf
: サービスのコンテナーに入れたいファイルを置きる場所。今はnginxのvhost.conf
だけあります。 -
prod.<service-name>.dockerfile
: 本番で利用するイメージをビルドする指定のdockerfile
。 -
prod.docker-compose.yml
: 本番環境のdocker-compose
設定。 -
dev.<service-name>.dockerfile
: 開発環境でサービスのイメージをビルドするdockerfile
。 -
dev.docker-compose.yml
: 開発環境のdocker-compose
設定。
理由:
- 本番と開発環境の設定が違うので、
dockerfile
とdocker-compose.yml
も別にします。 -
www
ディレクトリはLaravelに関係するファイルだけを設置したいです。dockerに関するのは上にします。
この構造の問題:
-
dockerfile
の数はサービスの数と一緒に上がります。サービスが増えると、ファイルが多くて見難くなります。 - 他のモージュルの
xdebug
、phpadmin
などについてはまだ考えません。追加すると構築が難しくなるかわかりません。
ひとまずこれで次に勧めます。
2.docker-compose.yml
各設定ファイル内容を説明するという形式ですすめたいと思います。まずはdocker-compose.yml
です。
2.1. appサービス
version: '3'
services:
# The Application
app:
image: myrepo/laravel-app
working_dir: /var/www
volumes:
- /var/www/storage
environment:
- "DB_HOST=database"
- "REDIS_HOST=cache"
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
tty: true
ports:
- "9000:9000"
-
version: '3'
: docker-composeのバージョン。このバージョンは2よりswarmモードをよくサポートすると言われますので、このバージョンをすすめます。 -
image: myrepo/laravel-app
サービスが利用するイメージ。このイメージをビルドやり方は前述にお話します。 -
volume
記載されるボーリュームはcontainerがストップされても残るように宣言。laravelとしては、このディレクトリはログとキャッシュviewを保存しますね。 -
enviroment
環境変数を宣言します。Laravel利用する変数は.env
だけにいれてもいいと思います。 -
logging
ログ形を宣言します。私は「json-file」を選びます。 -
tty: true
この項目はあまりわかりませんが、宣言しないとサービスが始まる途端すぐに止まることがあります。デプロイする時にこのサービスは自分自身のターミナルがなくて、pseudo terminal
指定しない問題になるかなと思います。 -
ports:
ホストの9000ポートをサービスの9000ポートに紐付けます。
2.2. webサービス
# The Web Server
web:
image: myrepo/laravel-web
ports:
- 80:80
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
depends_on:
- app
depends_on
: webはappサービスに依存するという関係を宣言します。記載しなくて、webサービスがappより先に
起動すると、nginxでappが見つからないエラーになります。
2.3. databaseサービス
# The Database
database:
image: mysql:latest
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=homestead"
- "MYSQL_USER=homestead"
- "MYSQL_PASSWORD=secret"
- "MYSQL_ROOT_PASSWORD=secret"
ports:
- "33061:3306"
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: 10
2.4. redisサービス
# redis
cache:
image: redis:3.0-alpine
database
と redis
サービスは公開のmysqlとredisイメージを利用します。
設定はこれで終わります。本番環境にこのファイルを投げればokだと思います!
次はapp
とweb
サービスが利用するイメージをビルドする仕方を話したいと思います。
3.docker イメージをビルド
前提:
docker hub アカウント所持しています。
例として、こらからはそのアカウント名は「myrepo」とします。
3.1. myrepo/laravel-app
イメージをビルド
3.1.1. dockerfile
を用意
prod.app.dockerfile
FROM php:7.0.4-fpm
COPY ./www/.env.prod ./www/.env
COPY ./www /var/www
WORKDIR /var/www
RUN apt-get update -y && apt-get install -y zip unzip
RUN docker-php-ext-install pdo mbstring
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& php composer.phar install --no-dev --no-scripts \
&& rm composer.phar
RUN chmod -R 777 /var/www/storage \
/var/www/bootstrap/cache
RUN php artisan key:generate
RUN php artisan config:clear
RUN php artisan config:cache
RUN php artisan optimize
-
FROM php:7.0.4-fpm
: ベースイメージの宣言
COPY ./www/.env.prod ./www/.env
COPY ./www /var/www
ソースコードをコピーします。.env.prod
を事前に用意しました。
-
RUN apt-get update -y && apt-get install -y zip unzip .. && rm composer.phar
: zip, unzip, pdo, mbstring, composerをインストールします - 最後のところのコマンドはLaravelセットアップコマンドですね。
3.1.2. dockerfile
でイメージをビルド
docker build -f prod.app.dockerfile -t myrepo/laravel-app .
成功であれば、Successfully tagged myrepo/laravel-app:latest
が表示されますね。
3.1.3. docker hubにイメージをプッシュ
docker login
docker push myrepo/laravel-app
appのイメージが制作できました!次の webのイメージビルドも同じです。
3.2. myrepo/laravel-web
イメージをビルド
3.2.1. dockerfileを用意
prod.web.dockerfile
FROM nginx:1.10-alpine
ADD conf/web/prod.vhost.conf /etc/nginx/conf.d/default.conf
COPY ./www/public /var/www/public
public
ディレクトリのコピーで、staticファイルを参照しはやくなるようにと言われるので、してみました。
vhost.conf
server {
listen 80;
index index.php index.html;
root /var/www/public;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
sendfile off;
}
}
3.2.2. dockerfile
でイメージをビルド
docker build -f prod.web.dockerfile -t myrepo/laravel-web .
3.2.3. docker hubにイメージをプッシュ
docker push myrepo/laravel-web
これで必要なイメージが出来上がりました!
本番で構築を実行する前にチェックのため開発の環境で一度実行しましょうか。ということで、次は開発環境で、本番環境を仮として実行します。
4. 開発環境で本番環境構築を実行してみます
docker swarm
モードを利用するということで、swarmモードを初期化します。
docker swarm init #init swarm mode
stackにデプロイ:
docker stack deploy --compose-file prod.docker-compose.yml mysrv
mysrv
は全体サビースの名前です。任意に好きな名前でしました。
docker stack deploy
を実行した後、走っているサビース(docker service ls)やプロセス(docker ps)をチェックすることができます。
自分の場合はdocker ps
結果は以下です。
my@mymy:~/Projects/mysrv$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
811e818e83b9 myrepo/laravel-web:latest "nginx -g 'daemon ..." 3 minutes ago Up 3 minutes 80/tcp, 443/tcp mysrv_web.1.hogvz22nxo19b1w92ev3pu5xz
426b99609e97 myrepo/laravel-app:latest "php-fpm" 3 minutes ago Up 3 minutes 9000/tcp mysrv_app.1.n763hd569tu5hxd3u6m3ee02e
6a02ce819570 mysql:latest "docker-entrypoint..." 3 minutes ago Up 3 minutes 3306/tcp mysrv_database.1.sc8j9xvqmkaotyjpotol9nucf
5238474eba93 redis:3.0-alpine "docker-entrypoint..." 3 minutes ago Up 3 minutes 6379/tcp mysrv_cache.1.qbtraxvu6kcchiwm6w5sjkgsj
deploy成功で問題がなければ、ブラウザーで結果を確認できます:http://0.0.0.0/
デフォルトのLaravel画面が表示すると想定します。
Note :
開発の時に私は使っていたコマンドはdocker stack
ではなく、docker-compose up
でした。
docker-compose up
を本番で実行することができます。でも swarm モードではないので、いろいろな制限があります。
違うところはdockerの公開ページとここなどに参考することができます。
開発で本番構築を実行しても問題なくということで、本番で実行しましょう!
5. 本番で構築を実行
本番で実行するのは前述で述べたのと全く同じです!初回時の基本なステップを話します。
-
prod.docker-compose.yml
を本番にコピー
コマンドのscp
などで、ファイルを本番に上げます。 -
swarmを初期化
docker swarm init
-
docker stack deploy --compose-file prod.docker-compose.yml mysrv
-
servicesとprocessが正常に動くかをチェック
~/myproject $ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
fvoyz57upgxr mysrv_app replicated 1/1 myrepo/laravel-app:latest *:9000->9000/tcp
jq491ivl1cid mysrv_database replicated 1/1 redis:3.0-alpine *:33061->3306/tcp
ltr1yqrny80b mysrv_web replicated 1/1 myrepo/laravel-web:latest *:80->80/tcp
s4laek150xv7 dockercloud-server-proxy global 1/1 dockercloud/server-proxy *:2376->2376/tcp
docker service ls
で、mysrv
の3つの子供サービスが上がったと確認しました。
サーバーのipは x.x.x.x
であれば、http://x.x.x.x でLaravel
のデフォルト画面が表示すると思います。
上は自分のawsサーバーに上がった結果です。
ダウドしたい時はdocker stack rm mysrv
を実行します。
これで終わります!
ソースコードは下記です。
https://github.com/mytv1/sample-docker-laravel-prod
終わりに
サーバー構築についてあまり経験がない私は簡単なLaravelプロジェクトを上げました。
nginx, mysqlなどのイメージはもうdocker hubで用意されていてよかったと思います。swarmのおかげで、将来はいろいろサーバー構築コストも削減できればよかったと思います。
参考