SurrogatorのDockerイメージを作る


## 概要＆動機
1. Let's Chatのアイコンをローカルで(＝gravatar.comとの連携なしで)変えたい
1. [Let's Chat の gravatar がみんな同じでつらい→Surrogator 使ってみた](http://qiita.com/kounoike/items/86a2ab82f69e7d7a5550)で紹介されているとおり、[Surrogator](https://github.com/cweiske/surrogator)を使えば実現できるらしい
1. SurrogatorをDockerでサクっと入れたい
1. Docker HubではSurrogatorのDockerイメージが公開されていない
1. **ないなら自分で作ればいいよ！**
  - (作ってDocker Hubへ登録しました。[rprev/surrogator](https://hub.docker.com/r/rprev/surrogator/))


## 環境
- Dockerホストの環境は以下の通り。CentOS7+最新版のDockerです。

    ```shell-session
    # cat /proc/version
    Linux version 3.10.0-327.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu Nov 19 22:10:57 UTC 2015
    # docker -v
    Docker version 1.11.2, build b9f10c9
    ```

## 手順
- CentOSのオフィシャルイメージをFROMに指定し、httpサーバとphp、Surrogatorを導入するDockerfileを作る方法です。

1. Dockerileを作成します。

    ```bash:surrogator/Dockerfile
    FROM centos
    MAINTAINER rprev

    ENV container docker
    RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
    rm -f /lib/systemd/system/multi-user.target.wants/*;\
    rm -f /etc/systemd/system/*.wants/*;\
    rm -f /lib/systemd/system/local-fs.target.wants/*; \
    rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
    rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
    rm -f /lib/systemd/system/basic.target.wants/*;\
    rm -f /lib/systemd/system/anaconda.target.wants/*;
    VOLUME [ "/sys/fs/cgroup" ]

    RUN yum -y install httpd php php-gd curl; yum clean all; systemctl enable httpd.service
    RUN sed -i '/<Directory "\/var\/www\/html">/,/<\/Directory>/ s/AllowOverride [Nn]one/AllowOverride All/' /etc/httpd/conf/httpd.conf \
     && sed "/AddHandler cgi-script/a \ \
       <FilesMatch \\\\.php$>\n \
           SetHandler application/x-httpd-php\n \
       </FilesMatch>" \
       /etc/httpd/conf/httpd.conf
    RUN curl -s -L https://github.com/cweiske/surrogator/tarball/master | tar xvz -C /opt/ \
     && mv /opt/*surrogator* /opt/surrogator \
     && cp /opt/surrogator/data/surrogator.config.php.dist /opt/surrogator/data/surrogator.config.php \
     && cp /opt/surrogator/www/avatar.php /var/www/html/ \
     && cp /opt/surrogator/www/.htaccess /var/www/html/ \
     && sed -i -e 's/__DIR__ . //;' -e 's#/../data#/opt/surrogator/data#' /var/www/html/avatar.php

    EXPOSE 80
    CMD ["/usr/sbin/init"]
    ```

1. ビルドします。

    ```shell-session
    # docker build -t rprev/surrogator surrogator/
    ```

1. コンテナを立ち上げます。

    ```shell-session
    # docker run -d -p "80:80" --cap-add SYS_ADMIN rprev/surrogator
    ```

1. 接続できるか確認します。

    ```shell-session
    # curl http://localhost:80/avatar/
    Hash has to be 32 or 64 characters long
    ```

## 手順(旧)

- Docker Hubの[phpオフィシャルリポジトリ](https://hub.docker.com/_/php/)で公開されているphp7+apacheのDockerfileをSurrogator用にカスタマイズする方法です。
- 元々はphp7+apacheのイメージをFROMに指定して新しいDockerfileを作るつもりでしたが、紆余曲折あって大分回り道をしてしまいました。 何も考えずにオフィシャルイメージを使えばよいというわけではない、ことの教訓として残しておきます。

1. phpのオフィシャルリポジトリをcloneします。

    ```shell-session
    # git clone https://github.com/docker-library/php.git
    ```

1. Dockerfileをカスタマイズします。
    
    ```shell-session
    # cd php/7.0/apache/
    # git diff -- Dockerfile
    diff --git a/7.0/apache/Dockerfile b/7.0/apache/Dockerfile
    index b97d082..9539682 100644
    --- a/7.0/apache/Dockerfile
    +++ b/7.0/apache/Dockerfile
    @@ -17,7 +17,13 @@ RUN apt-get update && apt-get install -y \
                    libedit2 \
                    libsqlite3-0 \
                    libxml2 \
    +               libpng12-0 \
    +               libpng12-dev \
    +               libjpeg62-turbo \
    +               libjpeg62-turbo-dev \
    +               zlib1g \
                    xz-utils \
    +               git \
            --no-install-recommends && rm -r /var/lib/apt/lists/*
    
     ENV PHP_INI_DIR /usr/local/etc/php
    @@ -118,6 +124,9 @@ RUN set -xe \
                    --with-libedit \
                    --with-openssl \
                    --with-zlib \
    +               --with-gd \
    +               --with-jpeg-dir=/usr/local \
    +               --with-png-dir=/usr/local \
            && make -j"$(nproc)" \
            && make install \
            && { find /usr/local/bin /usr/local/sbin -type f -executable -exec strip --strip-all '{}' + || true; } \
    @@ -127,6 +136,13 @@ RUN set -xe \
    
     COPY docker-php-ext-* /usr/local/bin/
    
    +RUN git clone https://github.com/cweiske/surrogator.git /opt/surrogator \
    +       && cp /opt/surrogator/data/surrogator.config.php.dist /opt/surrogator/data/surrogator.config.php \
    +       && cp /opt/surrogator/www/avatar.php /var/www/html/ \
    +       && cp /opt/surrogator/www/.htaccess /var/www/html/ \
    +       && perl -i -pe 's#__DIR__ . ##; s#/../data#/opt/surrogator/data#' /var/www/html/avatar.php \
    +       && a2enmod rewrite
    +
     ##<autogenerated>##
     COPY apache2-foreground /usr/local/bin/
     WORKDIR /var/www/html
    # cd ../../..
    ```

1. ビルドします。

    ```shell-session
    # docker build -t rprev/surrogator php/7.0/apache/
    ```

1. コンテナを立ち上げます。

    ```shell-session
    # docker run -d -p "80:80" rprev/surrogator
    ```

1. 接続できるか確認します。

    ```shell-session
    # curl http://localhost:80/avatar/
    Hash has to be 32 or 64 characters long
    ```

### つまずいたこととその対処
- phpのオフィシャルリポジトリからDockerfileだけコピーしてきてビルドすると、lstat docker-php-source: no such file or directoryのようなエラーが発生する。
 - Dockerfile以外にもビルドで使用するファイルがリポジトリに含まれているため、リポジトリをcloneし、その中のDockerfileを使ってビルドすることにしました。


- Surrogatorをインストールし、`php surrogator.php`を実行すると、Fatal error: Uncaught Error: Call to undefined function surrogator\imagecreatefrompng()のようなエラーが発生する。
 - imagecreatefrompng()がないというエラーです。この関数を使うためにはGDを有効化する必要があるため、GD有効化のオプション(`--with-gd`)をつけてphpをビルドすることにしました。
 - また、[PHP マニュアル 関数リファレンス 画像処理および作成 GD インストール/設定](http://php.net/manual/ja/image.installation.php)によると、GDのコンパイルにはlibpngとlibjpegが必要で、libpngにはzlibが必要とのことなので、これらも`apt-get install`することにしました。


- libpng、libjpeg等を追加してビルドするとパッケージが見つからないというエラーが発生する。
 - オフィシャルイメージからコンテナを立ち上げ、その中で`apt-cache search libpng`等を実行して具体的なパッケージ名を確認し、そのパッケージ名を指定して`apt-get install`することにしました。


- libpng3、libjpeg-turbo-progs等を追加してビルドするとconfigure: error: pnglib.h not found.のようなエラーが発生する。
 - [【PHP】5.2.8 インストール Linux](http://blog.77jp.net/php-528-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-linux)の「エラーの例　その3」を参考に、開発者用のパッケージ(-dev)を`apt-get install`することにしました。

## その他
- Let's Chatとの連携は別記事で。