タグ: Docker

vagrantのshell provisionerにrun: “always”オプションを使うことでvagrant upするたびにdocker-composeを実行させる

開発環境をVagrantDocker(docker-compose)で構築したのですが、毎回コンテナを起動するために

  1. vagrant up
  2. SSHでゲストOSにログイン
  3. ゲストOS上でdocker-compose up

という手順を踏んでいました。

VagrantとDockerを使ったPHP実行環境を生成するサービス:PHPDocker.io – PHP and Docker development environment generator で生成されるVagrantfileを見ると、以下の方法でdocker-composeを起動させていました。

    # Bring up containers
    config.vm.provision "shell", run: "always", inline: "cd /home/docker/sample/phpdocker && docker-compose up -d 1>&2"

runオプションはProvisionerの共通オプションで、デフォルトでは最初のvagrant upでのみprovisionerが実行されますが、alwaysを指定することで、vagrant up, vagrant reloadのたびに実行されるようになります。

実際には以下のようにして使っています。

冒頭の3.のdocker-compose upはserver.shというスクリプトに書いてserver.sh upとして使っていました。

#!/bin/bash -eu

PWD=$(cd $(dirname $0); pwd)
PROJNAME=sampleproject

ARGS=
if [ $# -eq 0 ];then
    ARGS="up -d"
else
    ARGS=$@
fi

cd $PWD && docker-compose -p $PROJNAME $ARGS

Vagrantfileに以下の内容を追加しました。

  config.vm.provision "shell", run: "always", inline: "[ -f /home/vagrant/sampleproject/server.sh ] && /home/vagrant/sampleproject/server.sh"

プライベートGyazoサービスの構築

スクリーンショットをサーバにアップロードしてURLで共有できるGyazoというサービスがあります。
このOpen Source ClientのコードがGitHubにあるので、これでプライベートGyazoサービスを構築します。

今回の構成は

  • クライアント
    • Windows 10
    • gyazo/Gyazowinをもとにアップロード先URLを変更したものを作成
  • サーバー
    • Ubuntu 14.04
    • gyazo/GyazoのServerにあるRubyスクリプトを使う
    • Gyazoサーバプログラムはインストールから動作までDocker内で行う
    • アップロードされた画像、プログラム内部で利用するデータベースのような動的生成されるデータはdockerのマウント機能を使ってサーバ上に保存する

という形にしました。

サーバー側

必要なもの

  • Docker (記事執筆時に利用したのは1.7.1)
  • サービス用のドメイン

ドメインは http://~ でアクセスできるようにDNSで関連付けておいてください。

今回はgyazo.example.jpとしました。

  1. Gyazo用のディレクトリを作成
    mkdir gyazo
    cd gyazo
    
  2. Dockerfileを作成

    11行目の[SERVERDOMAIN]はサービス用のドメインに置き換えてください。

    例)

    RUN sed -i -e "s/gyazo.com/gyazo.example.jp\/data/" /usr/local/apache2/htdocs/upload.cgi
    
  3. イメージを作成

    docker buildでイメージを作成します。イメージにgyazoという名前を付けます。

    docker build --rm -t gyazo .
    
  4. gyazoイメージからgyazoという名前でコンテナを起動する
    docker run -d -p 80:80 --name gyazo -v `pwd`/data:/usr/local/apache2/htdocs/data -v `pwd`/db:/usr/local/apache2/htdocs/db gyazo
    
  5. http://gyazo.example.jp にアクセスして動作を確認

    「It’s works」がでればOK。

    Itsworks

クライアント側

必要なもの

  • Visual Studio 2015 Community (本記事ではインストール時に既定でインストールしています)
  1. ソースコードの取得

    gyazo/Gyazowinからソースコードをクローン、またはダウンロードします。今回はZIPでダウンロードしました。

  2. ZIPを展開して中にある、「gyazowin.sln」をダブルクリックで開く

    gyazowin.slnはVisual Studio 2015よりも古いフォーマットのファイルのため、アップグレード警告が表示されます。そのままアップグレードします。
    またVC++の開発環境がない場合、ここで追加インストールのウィザードが始まるのでインストールしたのち、gyazowin.slnを開きなおします。

    Upgrade_1Upgrade_2Upgrade_3

    InstallVC_2
    InstallVC_3

  3. コードの編集

    gyazowinはスクリーンショット画像をgyazoに送信する機能を持っていますが、送信先はソースコードにハードコーティングされているため、そこを今回用意したサーバへ変更します。

    gyazowin.cppの794行目のupload.gyazo.comgyazo.example.jpに変更します。

    Diff_gyazowin

  4. ビルドの実行

    1. メニュー「ビルド」の下にあるソリューション構成を「Debug」から「Release」に変更する
      Build Settings
    2. メニュー「ビルド」→「ソリューションのビルド」でビルドを実行

    正常に終了すれば、Releaseディレクトリが作成され、中にgyazowin.exeが生成されます。

  5. 実行確認

    1. gyazowin.exeを実行する
    2. カーソルが十字になる
    3. スクリーンショットを撮りたい範囲の左上をクリックしたまま、右下までドラッグ
    4. 指を話すと、スクリーンショットがgyazo.example.jpにアップロードされたのち、アップロード先URLで既定のブラウザが起動される。
      Gyazowinフォルダのエクスプローラをスクリーンショットしたもの
    5. サーバのdockerを起動したディレクトリの直下にdataディレクトリが作成され、そこにアップロードされた画像が配置する
      server_upload_images

備考

参考

Dockerコンテナをホスト名で参照できるDNSサーバコンテナ「dnsdock」を使う

ホストとなるサーバ上にA,Bの2つのコンテナが稼働しているとき、片方のコンテナからもう片方のコンテナを参照したいときは、簡単な方法はdockerコマンドの–linkオプションを使います。

これとは別に、ホスト名を使うことにより各コンテナを参照することができるコンテナがdnsdockです。
これを使うと–linkオプションなしで相互のコンテナにアクセスできます。
dnsdockはskydockをもとに簡易化したものです。

※コンテナ同士のやり取りは前提としてDockerデーモンのiccパラメータがtrue(デフォルト)で、アクセスされたいコンテナがexposeでポートをさらしている必要があります。

使用例

前提

  • ホストのOSはubuntu14.04
  • ホストのプロンプトを(host),コンテナのプロンプトを(コンテナ名)とする
  • rootは#、ユーザーは$とする

今回は、php(php:5-apache)とmysql(mysql:5.6)のコンテナを使い、

  • ホストからmysqlコマンドでmysqlコンテナにアクセス
  • ホストからcurlコマンドでphpコンテナにアクセス
  • phpコンテナからでmysqlコンテナにアクセス

をしてみます。

1.ホスト側の設定(要root)

Dockerのネットワークを172.17.0.1/24にして、コンテナが参照するDNSを172.17.0.1にする。

  • Dockerデーモンの起動オプションにbipとdnsを加えて、サービスを再起動

    /etc/default/docker

    DOCKER_OPTS="--bip=172.17.0.1/24 --dns=172.17.0.1 --dns=8.8.8.8"
    

    ※各コンテナは172.17.0.1をデフォルトのDNSとしてdnsdockを通して名前解決を行うが、dnsdockが停止していると名前解決が行えないので予備も設定しておく

    (host)# service docker restart
    
  • ネームサーバに172.17.0.1を/etc/resolv.confのnameserverの先頭に加える。直接加えると再起動時に消えるので、resolvconfを利用する

    /etc/resolvconf/resolv.conf.d/head

    nameserver 172.17.0.1
    
    (host)# resolvconf -u
    

2.作業領域と確認用コードの作成

(host)$ mkdir work
(host)$ cd work
(host)$ mkdir src
(host)$ echo '<?php echo "Hello World\n"; ' > src/index.php

3.dnsdockコンテナの起動

(host)$ docker run -d --name dnsdock -v /var/run/docker.sock:/var/run/docker.sock -p 172.17.0.1:53:53/udp aacebedo/dnsdock:latest-amd64

(追記 2016/10/14)Githubのページがtonistiigi/dnsdockからaacebedo/dnsdockに変更されたのに伴ってコンテナイメージをaacebedo/dnsdock、バージョンをDocker Hubに従ってlatest-amd64に変更しました。
(追記 2016/8/24)issueがcloseされ、clouddynamics/dnsdockがなくなりました
※dnsdockの本家は tonistiigi/dnsdock だが、ホストからアクセスする際にバグがあり、対応されたものが clouddynamics/dnsdock にあるためコンテナイメージはそちらを利用しています。
参考:dig dnsdocker.docker works, curl dnsdocker.docker doesn’t · Issue #34 · tonistiigi/dnsdock

  • digコマンドで名前が解決できるか確認

    (host)$ dig *.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> *.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24923
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;*.docker.                      IN      A
    
    ;; ANSWER SECTION:
    *.docker.               0       IN      A       172.17.42.2
    
    ;; Query time: 1 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:12:05 JST 2016
    ;; MSG SIZE  rcvd: 50
    

4.MySQLコンテナとPHPコンテナの起動

(host)$ docker run -d --name some-mysql -e MYSQL_ROOT_PASSWORD=mysqlpass mysql:5.6
(host)$ docker run -d --name some-php -v $(pwd)/src:/var/www/html -p 80:80 php:5-apache
  1. 現在起動中のコンテナの確認

    (host)$ docker ps

    CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                    NAMES
    d70f295f19fb        php:5-apache            "apache2-foreground"     36 seconds ago      Up 34 seconds       0.0.0.0:80->80/tcp       some-php
    2b1323183779        mysql:5.6               "/entrypoint.sh mysql"   3 minutes ago       Up 3 minutes        3306/tcp                 some-mysql
    7258ecfbfd04        tonistiigi/dnsdock   "/go/bin/dnsdock"        7 minutes ago       Up 7 minutes        172.17.42.1:53->53/udp   dnsdock
    
  2. 起動したコンテナの名前解決を確認

    ホスト名は<anything>.<container-name>.<image-name>.<environment>.<domain>というルールになっており、デフォルトだと<domain>はdocker、<environment>は空文字列のため、<container-name>.<image-name>.dockerでアクセスできる。

    MySQLコンテナはmysqlイメージを使ってsome-mysqlという名前で起動したため、ホスト名はsome-mysql.mysql.docker

    (host)$ dig some-mysql.mysql.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> some-mysql.mysql.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14084
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;some-mysql.mysql.docker.       IN      A
    
    ;; ANSWER SECTION:
    some-mysql.mysql.docker. 0      IN      A       172.17.42.3
    
    ;; Query time: 0 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:20:11 JST 2016
    ;; MSG SIZE  rcvd: 80
    

    同様にPHPコンテナはphpイメージを使って、some-phpという名前で起動したのでホスト名はsome-php.php.docker

    (host)$ dig some-php.php.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> some-php.php.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30088
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;some-php.php.docker.           IN      A
    
    ;; ANSWER SECTION:
    some-php.php.docker.    0       IN      A       172.17.42.4
    
    ;; Query time: 0 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:21:15 JST 2016
    ;; MSG SIZE  rcvd: 72
    

5.ホストからPHPコンテナにホスト名でアクセスしてみる

(host)$ curl http://some-php.php.docker/index.php

Hello World

6.ホストからmysqlコマンドでMySQLコンテナにホスト名でアクセスしてみる

mysqlコマンドはあらかじめインストールしておく必要があります。
(ubuntu14.04ならapt-get install mysql-client-core-5.6)

(host)$ mysql -h some-mysql.mysql.docker -u root --password=mysqlpass

7.phpコンテナからmysqlにアクセス

7.1 PHPコンテナにPDOとMySQLのモジュールを組み込む

php:5-apacheにはPDOとMySQLのモジュールが組み込まれていないので、組み込む必要がある。

方法1 モジュール入りカスタムイメージを使う
  1. Dockerfileを作成する

    Dockerfile

    FROM php:5-apache
    RUN docker-php-ext-install pdo pdo_mysql
    
  2. イメージを作成する
    (host)$ docker build -t php:custom  .
    
  3. 動かしているsome-phpコンテナを終了させて、代わりにカスタムイメージで起動する
    (host)$ docker stop some-php
    (host)$ docker rm some-php
    (host)$ docker run -d --name some-php -v $(pwd)/src:/var/www/html -p 80:80 php:custom
    
方法2 現在動いているコンテナにモジュールをインストールする
  1. some-phpコンテナに入る
    (host)$ docker exec -it some-php bash
    
  2. モジュールをインストールする
    (some-php)$ docker-php-ext-install pdo pdo_mysql
    (some-php)$ exit
    
  3. コンテナ再起動
    (host)$ docker restart some-php
    

7.2 index.phpをPDOを使ってMySQLにアクセスするプログラムに書き換える

src/index.php

<?php

    $pdo = new PDO('mysql:host=some-mysql.mysql.docker;dbname=mysql', 'root', 'mysqlpass');
    $sth = $pdo->query("show tables");
    $sth->execute();
    $result = $sth->fetchAll();
    print_r($result);

7.3 ホストからアクセス

(host)$ curl http://some-php.php.docker/index.php

Array
(
    [0] => Array
        (
            [Tables_in_mysql] => columns_priv
            [0] => columns_priv
        )

    [1] => Array
        (
            [Tables_in_mysql] => db
            [0] => db
        )
     :
     :
     :

WEBインタフェース

dnsdockにはRESTインタフェースを持っているので、curlなどで問い合わせやデータの更新ができます。

tonistiigi/dnsdock#HTTP Server

整形にjqコマンドを使用しています。

コンテナの一覧

curl -s http://dnsdock.docker/services|jq .

{
  "672963efeef98b3c473f87f7ede66e51f661cc6f5f28075c79ec44c633d2a564": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.2",
    "Image": "dnsdock",
    "Name": "dnsdock"
  },
  "2d17b46d944919797ed4f62d9c763e240cf2ed511573f22b438b07ba3239f77b": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.4",
    "Image": "php",
    "Name": "some-php"
  },
  "263c0325f15f0f4c95f68f1975df5a50104ca766529c772d29d9a1357b8fab17": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.3",
    "Image": "mysql",
    "Name": "some-mysql"
  }
}

参考

(追記 2016/10/14)
記事執筆時はアドレスとして172.17.42.1を使用していましたが、

ERROR: for dnsdock  Cannot start service dnsdock: driver failed programming external connectivity

というエラーが出るようになったため、下記及びaacebedo/dnsdockを参考に172.17.0.1に変更したらうまく動作するようになりました

1.9: Default docker0 IP is not 172.17.42.1 for new installs · Issue #17305 · docker/docker

DockerのOfficial imageのMySQLを使って初回起動時にカスタムSQLを実行させる

DockerのOfficial RepositoriesMySQLを使って、初回のDBデータ作成時に、カスタムSQLを実行する。

MySQLイメージは起動時にMySQLデータディレクトリ(/var/lib/mysql)の中身がない場合、mysql_install_dbなどが実行されます。その処理の中で、 /docker-entrypoint-initdb.dディレクトリにシェルスクリプトや、SQLが存在する場合、それを実行してくれる仕組みがあります。

サンプル

サンプルとして、Docker Composeを使って、PHPMyAdminとMySQLサーバを構築してみます。
その際、初回起動時に2つのデータベースと1つのテーブルを作成します。
うち1つは環境変数MYSQL_DATABASEをセットすることによって自動的に作成されるデータベース、それ以外がdocker-entrypoint-initdb.dによるものです。

ローカルにinitdb.dフォルダを作成し、それをMySQLイメージ中のdocker-entrypoint-initdb.dにマウントさせます。

initdb.dフォルダには、create_another_db.shとcreate_table_in_exampledb.sqlを置いておきます。

docker-compose upでMySQLが立ち上がると、最後にそれらのファイルが実行されます。

create_another_db.shはDBを新規作成します。シェルなので、環境変数を参照できます。
MySQLへの流し込み方法は、docker-entrypoint.shを参考にパスワードを追記した形です。

create_table_in_exampledb.sqlは環境変数MYSQL_DATABASEによって既に作成されているDBに対してテーブルを作成します。

全部入りはこちら→mistymagich/docker-mysql-sample

参考

Docker MySQLイメージのクエリログ(General Query Log)出力

mysql Repository | Docker Hub Registry – Repositories of Docker Imagesのクエリログを見る方法

方法1.クエリログをファイル出力して、ログディレクトリをデータボリュームでマウント

  1. log.cnf(クエリログを出力するように設定したMySQLの設定ファイル)とDockerfileを作成する

    log.cnf

    [mysqld]
    log_output=FILE
    general_log=1
    general_log_file=/var/log/mysql/query.log
    

    Dockerfile

    FROM mysql
    ADD log.cnf /etc/mysql/conf.d/log.cnf
    RUN chmod 644 /etc/mysql/conf.d/log.cnf
    
  2. ビルド
    $ docker build -t mysql_custom .
    
  3. ログディレクトリを作成
    $ mkdir mysqllog
    
  4. Docker側のMySQLが書き込みできるように権限を与える
    $ chmod 777 mysqllog
    
  5. Docker実行
    $ docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -v `pwd`/mysqllog:/var/log/mysql -p "3306:3306" -d mysql_custom
    
  6. クエリログの参照
    $ sudo tail -f mysqllog/query.log
    
  7. 上記出力したまま、別端末でMySQLサーバにログインしてクエリを発行し、記録していることを確認
    $ MYSQL_PWD=my-secret-pw mysql -u root -h 127.0.0.1 -P 3306
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    +--------------------+
    3 rows in set (0.00 sec)
    
    150729 12:02:11     6 Connect   root@172.17.42.1 on
                        6 Query     select @@version_comment limit 1
    150729 12:02:12     6 Query     show databases
    150729 12:02:14     6 Quit
    

Dockerfileを使わない方法

mysqlイメージは、/etc/mysql/conf.dに追加の設定ファイルを入れておけば、起動時に読み込む仕組みのため、docker run 時にマウントすることでDockerfileを省略できる。

設定ファイルを保存するディレクトリを作り、先ほどのlog.cnfを移動する。

mkdir mysqlconf
mv log.cnf mysqlconf/

/etc/mysql/conf.dにマウントさせて起動させる。

docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -v `pwd`/mysqllog:/var/log/mysql -v `pwd`/mysqlconf:/etc/mysql/conf.d -p "3306:3306" -d mysql

方法2.クエリログの出力先を標準出力にする

kolypto/docker-mysqlを参考に

log.cnfを以下のようにする

[mysqld]
log_output=FILE
general_log=1
general_log_file=/dev/stdout

起動する

docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -v `pwd`/mysqlconf:/etc/mysql/conf.d -p "3306:3306"  mysql

しかし、起動中に

[ERROR] Could not open /dev/stdout for logging (error 2). Turning logging off for the whole duration of the MySQL server process. To turn it on again: fix the cause, shutdown the MySQL server and restart it.

となり、クエリログは出力されませんでした。

Dockerのバージョンは

$ docker --version
Docker version 1.7.1, build 786b29d

docker execで実行中のMySQLイメージに入り、コマンドラインで書き込みをテストしてみる。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
bf5335a829bf        mysql               "/entrypoint.sh mysq   25 seconds ago      Up 24 seconds       0.0.0.0:3306->3306/tcp   boring_engelbart
$ docker exec -it bf5335a829bf bash
root@bf5335a829bf:/# apt-get update
root@bf5335a829bf:/# apt-get install -y sudo
root@bf5335a829bf:/# sudo -u mysql sh -c "echo test > /dev/stdout"
sh: 1: cannot create /dev/stdout: Permission denied

/dev/stdoutの権限を確認する。

root@bf5335a829bf:/# ls -l /dev/stdout
lrwxrwxrwx 1 root root 15 Jul 30 04:04 /dev/stdout -> /proc/self/fd/1
root@bf5335a829bf:/# ls -l /proc/self/fd/1
lrwx------ 1 root root 64 Jul 30 04:12 /proc/self/fd/1 -> /dev/pts/4
root@bf5335a829bf:/# ls -l /dev/pts/
total 0
crw-rw-rw- 1 root root 5, 2 Jul 30 04:04 ptmx

/dev/stderrも同様で、以下のissueが出ています。
Permission denied on /dev/stderr · Issue #6880 · docker/docker

ubuntuにphpenvからPHPをインストールした時のエラー

ubuntuをイメージベースに、phpenvを入れ、phpenvでPHP 5.6.9をインストールするDockerfileを作成。
docker buildしたのち、そのコンテナに入り、PHP 5.6.9をインストールした際、以下のようなエラーが発生した。

# phpenv install 5.6.9
[Info]: Loaded extension plugin
[Info]: Loaded apc Plugin.
[Info]: Loaded composer Plugin.
[Info]: Loaded pyrus Plugin.
[Info]: Loaded uprofiler Plugin.
[Info]: Loaded xdebug Plugin.
[Info]: Loaded xhprof Plugin.
[Info]: php.ini-production gets used as php.ini
[Info]: Building 5.6.9 into /root/.anyenv/envs/phpenv/versions/5.6.9
[Downloading]: http://php.net/distributions/php-5.6.9.tar.bz2
[Preparing]: /tmp/php-build/source/5.6.9
[Compiling]: /tmp/php-build/source/5.6.9
[Pyrus]: Downloading from http://pear2.php.net/pyrus.phar
[Pyrus]: Installing executable in /root/.anyenv/envs/phpenv/versions/5.6.9/bin/pyrus
[xdebug]: Installing version 2.3.2
[xdebug]: Compiling xdebug in /tmp/php-build/source/xdebug-2.3.2

-----------------
|  BUILD ERROR  |
-----------------

Here are the last 10 lines from the log:

-----------------------------------------
  write(sp[1], &s, sizeof(s));
       ^
/tmp/php-build/source/5.6.9/sapi/fpm/fpm/zlog.c: In function 'zlog_ex':
/tmp/php-build/source/5.6.9/sapi/fpm/fpm/zlog.c:191:8: warning: ignoring return value of 'write', declared with attribute warn_unused_result [-Wunused-result]
   write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len);
        ^
/tmp/php-build/source/5.6.9/sapi/fpm/fpm/zlog.c:195:8: warning: ignoring return value of 'write', declared with attribute warn_unused_result [-Wunused-result]
   write(STDERR_FILENO, buf, len);
        ^
PEAR package PHP_Archive not installed: generated phar will require PHP's phar extension be enabled.
-----------------------------------------

The full Log is available at '/tmp/php-build.5.6.9.20150605091024.log'.
[Warn]: Aborting build.

ビルドのためにインストールしたパッケージは以下の通り。

# apt-get install -y re2c bison libxml2-dev libcurl4-openssl-dev libjpeg8-dev libpng12-dev libmcrypt-dev libreadline-dev libtidy-dev libxslt1-dev

そこで、ubuntuにphp-buildでphp5.5を入れるためにシェルスクリプトと格闘した記録 | hirobanex.netより、autoconfをインストール

# apt-get install -y autoconf

もう一度インストールしなおす

# phpenv install 5.6.9
[Info]: Loaded extension plugin
[Info]: Loaded apc Plugin.
[Info]: Loaded composer Plugin.
[Info]: Loaded pyrus Plugin.
[Info]: Loaded uprofiler Plugin.
[Info]: Loaded xdebug Plugin.
[Info]: Loaded xhprof Plugin.
[Info]: php.ini-production gets used as php.ini
[Info]: Building 5.6.9 into /root/.anyenv/envs/phpenv/versions/5.6.9
[Skipping]: Already downloaded and extracted http://php.net/distributions/php-5.6.9.tar.bz2
[Preparing]: /tmp/php-build/source/5.6.9
[Compiling]: /tmp/php-build/source/5.6.9
[Pyrus]: Downloading from http://pear2.php.net/pyrus.phar
[Pyrus]: Installing executable in /root/.anyenv/envs/phpenv/versions/5.6.9/bin/pyrus
[xdebug]: Installing version 2.3.2
[xdebug]: Compiling xdebug in /tmp/php-build/source/xdebug-2.3.2
[xdebug]: Installing xdebug configuration in /root/.anyenv/envs/phpenv/versions/5.6.9/etc/conf.d/xdebug.ini
[xdebug]: Cleaning up.
[Info]: Enabling Opcache...
[Info]: Done
[Info]: The Log File is not empty, but the Build did not fail. Maybe just warnings got logged. You can review the log in /tmp/php-build.5.6.9.20150605093249.log
[Success]: Built 5.6.9 successfully.

作成したDockerfile

Dockerで作るPHPの実行環境サンプル

ファイル一式: https://github.com/mistymagich/vagrant-docker-php

php,nginx,mysqlのコンテナを動かして、PHPを実行させるサンプル環境です。

vagrantとvirtualboxもしくはdockerがインストールされているlinuxから起動できます。

必要なもの

  • Vagrantを使う方式
  • Dockerから起動する方式
    • DockerがインストールされたLinux
      バージョン 1.5.0 以上

セットアップ

  • Vagrantを使う方式
        > git clone https://github.com/mistymagich/vagrant-docker-php.git
        > cd vagrant-docker-php
        > vagrant up
    

    CoreOSが立ち上がるので、PuTTYなどでSSHでログインする (接続先は vagrant ssh-configで確認)

        $ cd /vagrant
        $ /vagrant/docker-build.sh
    
  • Dockerから起動する方式
        $ git clone https://github.com/mistymagich/vagrant-docker-php.git
        $ cd vagrant-docker-php
        $ chmod +x *.sh
        $ sudo ./docker-build.sh
        $ sudo echo '127.0.0.1 sandbox.local' >> /etc/hosts
    

    Ubuntu/Debianでdockerコマンドが docker.io1 になっている場合、docker-build.sh、docker-run.shの

    DOCKER=docker
    

    DOCKER=docker.io
    

    に変更したのち実行する。

起動

$ sudo ./docker-run.sh

正常に起動できれば、ブラウザで

http://sandbox.local

でアクセスするとPHPInfoが表示されます。

MySQLコンテナとの接続サンプルは

http://sandbox.local/dbconnect.php

にあります。

構造

Nginxコンテナ

コンテナ名:sandbox-nginx

公式Nginxコンテナをもとに、ホスト名sandbox.localに対して、PHPコンテナを参照する設定追加しています。
ドキュメントルートはsrc/public
拡張子がPHPならPHPコンテナにあるPHP-FPMを通して実行されます。

MySQLコンテナ

コンテナ名:sandbox-mysql

公式MySQLコンテナをそのまま利用しています。

データの永続化はしていません。

docker-run.sh実行時にsrcディレクトリにあるinit.sqlを実行することで、データベース・テーブル・データのインポートを行っています。

sanbox.localに対して3306にアクセスすることでMySQLコンテナにアクセスできます。

ユーザー名はroot、パスワードはdocker-run.shでMySQLコンテナ起動時にMYSQL_ROOT_PASSWORDで指定している値です。(編集していない場合、mysecretpw)

PHP(FPM)コンテナ

コンテナ名:sandbox-php

公式PHPコンテナのFPMをもとに、以下のモジュールを追加しています。

  • pdo
  • pdo_mysql
  • gd
  • mysqli
  • mcrypt
  • mbstring
  • iconv

関係図

関係図

PHP(FPM)コンテナはホスト名mysqlでMySQLコンテナにアクセスできます。
Nginxコンテナはホスト名phpでPHP(FPM)コンテナを参照しています。

PHPMyAdminを動かすサンプル

  1. PHPMyAdminをダウンロード
  2. 解凍して、中にあるPHPファイルをsrc/publicにコピー(すでにあるファイルは削除する)
  3. config.sample.incをconfig.incにリネーム
  4. config.incを編集

    ホスト名を変更

     /* Authentication type */
     $cfg['Servers'][$i]['auth_type'] = 'cookie';
     /* Server parameters */
    -$cfg['Servers'][$i]['host'] = 'localhost';
    +$cfg['Servers'][$i]['host'] = 'mysql';
     $cfg['Servers'][$i]['connect_type'] = 'tcp';
    

    末尾に追加

     $cfg['CheckConfigurationPermissions'] = false;
    
  5. http://sandbox.localにアクセス
  6. ID:root / PW:mysecretpw (docker-run.shのMySQLコンテナ起動時のMYSQL_ROOT_PASSWORDで指定している値)

その他

  • docker-run.sh実行時にすべてのコンテナを削除します。
  • コンテナが正常に動かない場合、docker ps -aでコンテナIDを調べ、docker logs コンテナID で原因となるメッセージが出力されることがあります。

  1. Ubuntu/Debianの場合、dockerコマンドがdocker.ioになっているため、いまさら聞けないDocker入門(2):ついに1.0がリリース! Dockerのインストールと主なコマンドの使い方 (1/3) – @ITにあるようにしてdockerコマンドを利用できるようにする方法もあります。