Alpine Linux の Docker イメージで PHP の開発環境を構築する


概要
----

Alpine Linux の Docker イメージのファイルサイズが Ubuntu や Debian よりもはるかに小さいので、ダウンロード時間やビルド時間の短縮が期待されます。一方で、2016年4月時点では主要な公式イメージの Alpine Linux 対応が進行中なので、すべてを置き換えることはできません。

Debian を対象とした docker-compose.yml の例はこちらの[記事](http://qiita.com/masakielastic/items/9fdc52b47cc7e3850b9f) (「Docker Compose で PHP 7.0 の開発環境を構築する」) をご参照ください。Vagrant Box で PHP の開発環境の構築に関して、こちらの[記事](http://qiita.com/masakielastic/items/5a7bc6298de6e500a7dd)をご参照ください。


Alpine Linux に Docker をインストールする
-------------------------------------

Alpine Linux をホスト OS として Docker をインストールしてみましょう。apk リポジトリを追加します。

```bash:/etc/apk/repositories
http://dl-3.alpinelinux.org/alpine/edge/community
```

```
sudo apk update
sudo apk add docker
```

自動起動するサービスとして追加します。

```bash
sudo rc-update add docker boot
```

サービスを起動させます。

```bash
sudo service docker start
```

2016年4月時点で試したところ、Docker のデーモンがクラッシュするので、バイナリを直接インストールすることにしました。
まず前提要件となるパッケージ群をインストールします。

```bash
sudo apk add iptables git xz busybox musl
```

バイナリをダウンロードして展開した後でインストールします。

```bash
curl -O https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz
tar -xvzf docker-latest.tgz
sudo mv docker/* /usr/bin/
```

デーモンを起動させます。

```bash
sudo docker daemon &
```

デーモンが起動しているか確認してみましょう。

```bash
sudo docker version
```

sudo を使わなくても実行できるように usermod を実行します。shadow パッケージを導入します。

```bash
sudo apk add shadow
```
パスワードは `vagrant` です。

```bash
sudo usermod -aG docker vagrant
```

Alpine Linux に Docker Compose をインストールする
----------------------------------------------

配布されているバイナリが動かなかったので、Python のパッケージマネジャーの pip でインストールしました。

```bash
sudo apk add py-pip
sudo pip install docker-compose
```

バージョンを確認してみましょう。

```bash
docker-compose version
```

Debian の Docker イメージをダウンロードする際に次のようなエラーに遭遇しました。

```bash
Docker pull issue (ApplyLayer exit status 1 stdout: stderr: chmod /bin/mount: permission denied)
```

対策として、次のコマンドを実行することで解決しました。

```bash
# http://forum.alpinelinux.org/forum/general-discussion/docker-pull-issue-applylayer-exit-status-1-stdout-stderr-chmod-binmount
sudo sysctl -w kernel.grsecurity.chroot_deny_chmod=0
```

Hello World を表示させる
----------------------

Alpine Linux の公式イメージを動かしてみましょう。

```bash
docker run alpine /bin/echo 'Hello world'
```

タグでバージョンを指定することができます。

```bash
docker run alpine:3.3 /bin/echo 'Hello world'
```

ターミナルからコマンドを実行する
--------------------------


PHP のバージョンを表示させてみましょう。

```bash
docker run php:7.0-alpine php -v
```

今度はターミナルに入って php -v を実行してみます。

```bash
docker run -it php:7.0-alpine /bin/sh
# php -v
# exit
```

PHP のビルトインサーバーを起動させてみましょう。

```bash
docker run -it -p 80:80 php:7.0-alpine /bin/sh
cd home
echo test > index.html
echo "<?php phpinfo();" > index.php
php -S 0.0.0.0:80
```

PHP のビルトインサーバー
---------------------

最初の Docker Compose の練習として PHP のビルトインサーバーに取り組んでみましょう。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.3
    volumes:
      - ./www:/home
    command: /bin/true
  php:
    image: php:7.0-alpine
    expose:
      - '80'
    ports:
      - '80:80'
    volumes_from:
      - app
    working_dir: /home
    command: php -S 0.0.0.0:80
```

www docker-compose.yml と同じディレクトリに www フォルダーを用意して PHP スクリプトを設置します。

サービスを起動させてみましょう。

```bash
docker-compose up -d
```

サービスの停止は次のとおりです。

```bash
docker-compose stop
```

Apache Httpd
------------

まずは Httpd だけを動かしてみましょう。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.4
    volumes:
      - ./www:/usr/local/apache2/htdocs/
    command: /bin/true
  httpd:
    image: httpd:2.4-alpine
    ports:
      - '80:80'
    volumes_from:
      - app
```

今度は php-fpm と連携させてみましょう。

```yml:docker-compose.yml
app:
  image: alpine:3.4
  volumes:
    - ./www:/usr/local/apache2/htdocs
  command: /bin/true
php:
  image: php:7.1-fpm-alpine
  ports:
    - '9000:9000'
  volumes_from:
    - app
apache:
  build: ./
  ports:
    - '80:80'
  volumes_from:
    - app
  links:
    - php
```

```bash:Dockerfile
FROM httpd:2.4-alpine

RUN { \
  echo 'LoadModule proxy_module modules/mod_proxy.so'; \
  echo 'LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so'; \
  echo ''; \
  echo 'DirectoryIndex index.php index.html'; \
  echo '<FilesMatch \.php$>'; \
  echo '    CGIPassAuth On'; \
  echo '    SetHandler "proxy:fcgi://php:9000"'; \
  echo '</FilesMatch>'; \
} >> /usr/local/apache2/conf/httpd.conf
```

nginx
-----

次に nginx を試してみましょう。最初は HTML ファイルだけを試してみましょう。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.3
    volumes:
      - ./www:/usr/share/nginx/html
    command: /bin/true
  nginx:
    image: nginx:1.9-alpine
    ports:
      - '80:80'
    volumes_from:
      - app
```

次に php-fpm と連携させて PHP スクリプトを実行できるようにします。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.3
    volumes:
      - ./www:/usr/share/nginx/html
    command: /bin/true
  php:
    image: php:7.0-fpm-alpine
    ports:
      - '9000:9000'
    volumes_from:
      - app
  nginx:
    build: ./
    ports:
      - '80:80'
    links:
      - php
    volumes_from:
      - app
```

```bash:Dockerfile
FROM nginx:1.9-alpine
COPY default.conf /etc/nginx/conf.d/default.conf
```

```bash:default.conf
server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;

    location ~ \.php$ {
        fastcgi_pass   php:9000;
        fastcgi_index  index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}
```

サービスを起動させる前に Docker イメージをビルドします。

```bash
docker-compose build
```

サービスを起動させるときにビルドを指定することもできます。

```bash
docker-compose up --build -d
```

サービスを起動している間に修正した設定ファイルを反映させるために、コンテナを再生成することもできます。

```bash
docker-compose up -d --force-recreate
```


h2o (HTTP サーバー)
------------------

h2o の公式サイトのリンクで示されている lkwg82/h2o-http2-server を試してみましょう (2016年4月時点)。
まずは HTML ファイルだけの場合です。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.3
    volumes:
       - ./www:/var/www/html
    command: /bin/true
  h2o:
    image: lkwg82/h2o-http2-server:v1.7.1
    ports:
       - '80:80'
    volumes_from:
      - app
```

今度は php-fpm に対応させてみましょう。

```yml:docker-compose.yml
version: '2'

services:
  app:
    image: alpine:3.3
    volumes:
       - ./www:/var/www/html
    command: /bin/true
  php:
    image: php:7.0-fpm-alpine
    expose:
      - '9000'
    volumes_from:
      - app
  h2o:
    image: lkwg82/h2o-http2-server:v1.7.1
    ports:
      - '80:80'
    volumes:
      - ./conf:/etc/h2o
    volumes_from:
      - app
```

```bash:conf/h2o.conf
file.custom-handler:
  extension: .php
  fastcgi.connect:
    host: php
    port: 9000
    type: tcp
file.index:
  ['index.php', 'index.html']
hosts:
  default:
    listen:
      port: 80
    paths:
      /:
        file.dir: /var/www/html

access-log: /dev/stdout
error-log: /dev/stderr
```

h2o の Dockerfile は次のように用意することができる。

```bash:Dockerfile
FROM lkwg82/h2o-http2-server:v1.7.1

COPY conf/h2o.conf /etc/h2o/h2o.conf
```

Dockerfile を使う場合、docker-compose.yml で　`build` プロパティで指定する。

```bash:docker-compose.yml
services:
  h2o:
    build: ./
    ports:
    - '80:80'
    volumes_from:
      - app
```