Docker でnginx + PHP-FPM (+ Phalcon) + MySQL + Redis を構築してみた
巷で噂の Docker。
弊社でも主に開発環境の用途で使っていますよ!
そこで今回は、Webサービス開発の場面を想定した構成で Docker したいと思います!
目次
目標
nginx + PHP-FPM (+ Phalcon) + MySQL + Redis の環境を、Docker 使ってローカルに立ち上げて、ちょっと開発する
手順
1. Docker Toolbox のインストール
Docker Toolbox は、Docker 周りのツールいろいろをいっぺんに使えるようにしてくれる素敵なやつです!(ちょっとドキュメントが少なくて困ったけど…)
[bash]brew cask install dockertoolbox[/bash]
Mac だとこれだけですね!これで virtualbox と dockertoolbox のパッケージがインストールされます。
※ Windows 用も用意されてるようですのでチェックしてみてください!
Docker Toolbox で手に入るツールをまとめるとこんな感じです。
- Docker CLI クライアント
docker コマンドですね。
イメージやコンテナを作る Docker Engine を操作できます。 - Docker Machine
docker-machine コマンドですね。
Docker Engine のホストを作成・操作できるので、Mac 上のターミナルから Docker Engine のコマンドが使えるようになったり、AWSなどのリモートシステムにホストをデプロイできるようにもなります。 - Docker Compose
docker-compose コマンドですね。
複数コンテナの定義と実行ができるようになります。 - Kitematic
Docker のGUIツールです。 - Docker QuickStart Terminal
さっき起動したやつですね。
Docker のコマンドライン環境向けにあらかじめ設定されているシェルです。 - Oracle VM VirtualBox
チュートリアルにあるように、ちゃんとインストールされたか確認してみましょう!
Docker Quickstart Terminal.app を起動して、どのターミナルで立ち上げるか選択すると…
なんか処理走ってクジラが出ます!
さらに
[bash]docker run hello-world[/bash]
を叩いて、全部いい感じに処理されるかチェックするとのこと。
それー。
いけましたね。問題なさそう!
ちなみに docker run は、Dockerコンテナを作成・起動するコマンドになります。
メッセージを読むと、
Docker クライアントが Docker デーモンに接続できて、
Docker デーモンが Docker Hub から “hello, world”イメージを pull してこれて、
Docker デーモンがイメージからコンテナを作成できて、
Docker デーモンが Docker クライアントに出力を渡せたので、
このメッセージが見れてる、ということのようです。ふむ…。
いろいろ調べて整理した結果、
こう理解しました(ツッコミあれば2秒で修正します!
Docker Engine のデーモンは Linux上でしか動かない
↓
Docker Machine コマンド(と VirtualBox)使って、Mac上で Linux の VM が作成される
↓
Linux VM が Docker Engine をホストする
↓
Docker QuickStart シェル + Docker CLI で、(Mac上で動く)VM 上で動く Docker Engine を(特に設定なしで)操作することができる!
むずい!
2. docker compose 使って、各サービスを使えるようにする
さて、Docker 環境が手に入りました。
続いて、各サービスのコンテナを立ち上げましょう!
今回は nginx + PHP-FPM(+ Phalcon)+ MySQL + Redis な環境を作りたいのですが、それぞれのイメージを協調させて動かしたい時に、docker-compose が便利!ということのようです。
※ Docker Hubでイメージを調達
参考: Docker Hub 入門
※ 自分でイメージを作成
参考: Docker イメージの作成
ちなみに今回のイメージはすべて、Docker Hub にあがってたものを適当に選んで使ってみてる感じです!
※ Docker Hub のアカウントを作っておきましょう。
- nginx + PHP-FPM + Phalcon
https://hub.docker.com/r/alfonso/nginx-phalcon/
後ほどこのイメージを「web」というサービスとして使ってみます。 - MySQL
https://hub.docker.com/_/mysql/
こちらはオフィシャルのイメージ。「db」として使います。 - Redis
https://hub.docker.com/_/redis/
こちらもオフィシャルのイメージ。これはまんま「redis」として。
1. まずは作業用ディレクトリを作成
[bash]mkdir docker_test[/bash]
適当に作ります。今後はこのディレクトリの中にアプリケーションのコードを置いたり、定義ファイルを置いたりしていくことになります。
2. phalcon-devtools でプロジェクト作成
[bash]phalcon create-project sample[/bash]
サクッとプロジェクトを作ります(普段の業務ではあんまり使ってないですが…)。
コマンド叩くとディレクトリ構造がこうなります!
3. docker-compose.yml を定義
アプリケーションがどういうサービスを使って動くのか、YAML形式で定義します。
設定ファイルはこんな感じになります。サービスごとに必要な設定を記述する感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
[sourcecode lang="php"] version: '2' ← 設定の"書式"のバージョンみたいです。stringじゃないとダメ services: web: image: alfonso/nginx-phalcon ← イメージ作者名/イメージ名 ports: - "8000:80" ← "VM側のポート:コンテナのポート" alfonso/nginx-phalcon のドキュメントを参考にしました volumes: - ./sample:/var/www ← 先ほど作った sample を、コンテナの /var/www に対応させます environment: WEBPUBLIC: public ← この環境変数はこのイメージ独自のもので、ドキュメントルートのパスを指定するものです depends_on: ← db,redis が不可欠ってことと、web の前に db,redis が立ち上がるようにする設定です - db - redis db: image: mysql ← mysql:latest の省略形です environment: MYSQL_ROOT_PASSWORD: 'hoge' MYSQL_USER: 'sample' ← 指定すると起動時作成されます MYSQL_PASSWORD: 'hoge' ← 同上 MYSQL_DATABASE: 'sample' ← 同上 ports: - '3306:3306' ← VM側のポートは指定なしだとランダムになるようで、ローカルから接続できなくなるので指定 redis: image: redis ← redis:latest の省略形です ports: - '6379:6379' ← mysql の ports の設定と同様 [/sourcecode] |
4. docker-compose up でアプリケーションを立ち上げる
では立ち上げてみます!
[bash]docker-compose up[/bash]
ブオーっと流れて
止まりました。起動し終わったんでしょうか?確認したいけど、URLがわからず…。
調べてみると、Mac では VM の IPとポートを指定すればいいみたいなので、一度 Ctrl-c で停止して、docker-machine コマンドで確認してみます。
[bash]docker-machine ip default[/bash]
default はその名の通り、デフォルトの VM 名になります。
確認できました。
では今度は detach モードというバックグラウンド実行モードで立ち上げて、ブラウザから確認してみましょう!
[bash]docker-compose up -d[/bash]
すると…。
Thank you! ひとまず Phalcon が動いてることを確認できました。
続いて MySQL と Redis が起動・接続できていることを、ローカルから確認してみます!
ユーザ はroot 、パスワードは MYSQL_ROOT_PASSWORD で指定したものを入力しています。問題なく接続できてますね!(yml で別途設定している通り、sample / hoge でも接続できます)
また、Redis の方も接続できました!
4. MySQL と Redis と連携させつつちょっと開発してみる
ではせっかくなんでちょっと開発してみます!
今回は、MySQL にアクセスログを保存・表示しつつ、Redis でページアクセスをカウントして表示という、うんこアプリケーションを作ってみます!
1. DBコンテナ起動時のデータ投入
まずは、MySQL のテーブルを作りたいですね。
公式の MySQL イメージでは、コンテナ起動時にデータを投入できる仕組みが用意されているようで、コンテナの /docker-entrypoint-initdb.d 配下に .sh や .sql を配置しておくとそれらを実行してくれるという感じっぽいです。
こちらの記事が参考になりました!
DockerのOfficial imageのMySQLを使って初回起動時にカスタムSQLを実行させる
なので SQL ファイルを配置したローカルの任意のディレクトリを、コンテナ側の /docker-entrypoint-initdb.d としてマウントさせることにします。
1 2 3 4 5 6 7 8 |
[sourcecode lang="php" firstline="14" highlight="16,17"] db: image: mysql volumes: - ./initdb.d:/docker-entrypoint-initdb.d ← ローカル側ディレクトリは initdb.d としました。 environment: MYSQL_ROOT_PASSWORD: hoge [/sourcecode] |
こんな感じ。これで db コンテナの起動時に任意のデータが投入できます。
2. phalcon-devtools でモデルのソースコードを生成
再度 docker-compose up -d で db コンテナを再起動するとテーブルが作成されているので(※1)、app/config.php の DB 接続設定を修正しつつ、phalcon-devtools でモデルを生成しちゃいます。
この時、DB のホスト設定は、サービス名の “db” でOKです(ポートを変えていたら例えば “db:3307″とかに)。
参考: Networking in Compose
[sourcecode lang=”bash”]phalcon model –name access_log –get-set[/sourcecode]
※1 テーブルが作成されないこともあったり…。最終的には問題なくいったのですが、その条件がちょっと不明です…。
3. IndexController 実装して DB と連携してみる
リクエストごとにサーバ変数から値を取得して、DB に保存。過去のアクセス情報をリスト表示しているだけです。あと view もちょっといじって…
保存と取得ができているようです!(まあ、うんこですがね
そして次節、 Redis の連携で最後です!
4. Redis の php 拡張が入っていないことに気づき、Dockerfile で独自イメージを作ってみる
盲点でしたね。alfonso/nginx-phalcon には phpredis 入ってませんでした!
なので nginx-phalcon を元に、phpredis だけ追加したイメージを作って、それを使うことにします!
おもむろに、以下のような Dockerfile を作成します。
1 2 3 4 5 6 |
[sourcecode lang="text"] FROM alfonso/nginx-phalcon ← 元となるイメージを指定 RUN apt-get -y install php5-redis CMD service php5-fpm start && nginx RUN sleep 10s ← mysqld の起動より早く立ち上がるのでちょっと待ってて [/sourcecode] |
こんなノリで Dockerfile を書いてビルドするとイメージが作れちゃうんですね。
次に、docker-compose.yml の web の部分を編集して、nginx-phalcon イメージを使わず、この Dockerfile を元にしたイメージを使うようにします。
1 2 3 4 5 6 7 |
[sourcecode lang="php" firstline="2" highlight="4"] services: web: build: . ← docker-compose.yml と同階層の Dockerfile を元にイメージを作成する ports: - '8000:80' [/sourcecode] |
これで OK です!
Phalcon 側の Redis の接続設定を整えて、アクセスカウント用に Redis の incr を呼んだらできあがりです!
favicon のアクセス混ざっててよりうんこ感が増してますが、アクセスカウント取れてますね!
うまくいかない時は
今回端折っていますが、割とトライアンドエラーしました。
そういう時は以下のような形で確認してみるといいかもしれません。
- docker logs コマンドで、コンテナ起動時のログを確認
attach モード(-d オプションつけない)で起動しても確認できますが、コンテナを指定できるので便利です。 - コンテナ内のログファイルを直接 tail -f、どころかコンテナにログインも
[sourcecode lang=”bash”]docker exec -it <コンテナ名 or ID> tail -f /var/log/見たいログ [/sourcecode]
みたいな感じで、コンテナ内のファイルが参照できます。tail -f を bash とかに置き換えると普通に中に入れます。
まとめ
ちょっと長くなっちゃいましたが、Docker 素敵。