Travis CIでDockerを利用したらハマったしょうもない日記

こんにちは皆さん

CIっていい響きですよね！
継続的インテグレーション、なんて日本語に訳すとなんのことだかわからないところもおしゃれです。
現在ポピュラーなCIサービスといえば、github連携のTravis CIじゃないかと思います。
ここは自分もおしゃれ開発の仲間入りしたい！とばかりに、Travis CIを使ってみたのですが、昔普通にphp環境で組んだことがあったので、今回はdockerを使ってしまおうと思い至ったのです。

...まあ、オシャレで優雅に見える開発も、水面下で泥臭い検証実験を繰り返しているものです。
そんなわけで、Travis CI連携して、微妙にハマったところを徒然に記していきます。

# Travis CI

## CI (継続的インテグレーション: continuous integration)

そもそも、継続的インテグレーションって何でしょうね。
我々の業界では、基本的には以下の意味で使用されています。
「定時になる、もしくはコミットやプッシュをトリガーとし、自動的にビルドを行う仕組み」
ビルドっていうのは、「現在のソースコードから何らかの成果を出すこと」とのことで、コンパイルして実行ファイルを出力するのもビルドであれば、テストをしてその結果を出力することもビルドの一種です。

オープンソースでは、基本的にはテストを走らせることをビルドとしていますが、自前でサービスを開発するのなら、テストしてそれが通ってからデプロイするまでの一連の行動をビルドとすることが多いと思います。

このCIですが、いろんなサービスが有ります。

- Jenkins  : 自前の環境で好き勝手にカスタマイズできる定番のCIツール
- Travis CI: Githubと連携して`.travis.yml`に記載されている設定に従って、ビルドを行う。githubへのpushがトリガー
- Circle CI: Githubやその他のホスティングサービスと連携して、`circl.yml`の設定に従ってビルドを行う。プライベートリポジトリに対してもCIできる

その他にもいろいろありますが、メジャーどころはこんなところでしょう。

## Travis CI

大体のオープンソースプロジェクトには、ルートディレクトリに`.travis.yml`があったりするため、その界隈では一番流行っているのではないかと思います。
public なリポジトリであれば、無料で利用できます。
ちょっと追加で費用はかかりますが、privateなリポジトリをビルドしてデプロイまですることができます。

ビルドのは、masterへのpushの他、Pull Requestへのpushにも適用されます。
さらに、このビルドの結果はgithubにフィードバックされます。
これにより、現在のPull Requestがビルドに成功しているか、つまりテストを通しているかどうかが可視化されるため、マージしてよいかどうかの指標として使えます。
というか、テスト通っていないコードなんて、論外とばかりに弾けばコードを見渡す手間が省けるわけです。

Travis CIの利用開始はものすごく簡単です。
まず公式サイトに行きます。
https://travis-ci.org/

で、githubアカウントでログインできるというので、ログインします。
すると、以下の様な画面になります。

![travis.png](https://qiita-image-store.s3.amazonaws.com/0/102182/60c96b8e-2033-6d1e-cd3d-b3f102b9eb7a.png)

。。。もうやること書いてありますね。
まず、対象のリポジトリを選択して、チェック状態にします。
更新ボタンとか押さなくても大丈夫です( そもそもないし )。



で、`.travis.yml`をリポジトリに登録して、githubにpushすれば、それをトリガにしてビルドを初めます。

# DockerでCIした軌跡

[先日の記事](http://qiita.com/niisan-tokyo/items/ff793e271fd35b1a20bb)においてlaravelで掲示板を作ってテストも入れてみました。
こいつをCIに登録して、オシャレ開発の仲間入りをしましょう。
Travis CIでもDockerを使用できるとのことですので、自分の環境に限りなく近い環境を、Travis上に構築できると考えて、早速使うことにしたのです。
https://docs.travis-ci.com/user/docker/

初期の`.travis.yml`は以下の様な感じです

```.travis.yml
sudo: required
 
language: php

service: docker

before_install:
    - docker-compose up -d
    - docker-compose exec workspace composer install
    - cp .env.example .env
    - docker-compose exec workspace php artisan key:generate

script:
    - docker-compose exec workspace ./vendor/bin/phpunit 
```
ついでに`docker-compose.yml`も晒しておきます。

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

services:

    workspace:
        image: niisantokyo/laradock_ws
        volumes:
            - ./:/var/www/laravel
        tty: true

    mysql_test:
        image: mysql
        ports:
            - "3306"
        environment:
            MYSQL_DATABASE: homestead
            MYSQL_USER: homestead
            MYSQL_PASSWORD: secret
            MYSQL_ROOT_PASSWORD: root
```

## docker-composeがない

以下のログを吐き出し、ビルドが止まってました。

```
$ docker-compose up -d
/home/travis/build.sh: line 45: docker-compose: command not found

The command "docker-compose up -d" failed and exited with 127 during .

Your build has been stopped.
```
コマンドが見つからないだとぉ！？
何が悪いんだと思ったけど、そもそも`service`の項目が間違っているようで、以下のようにするべきだたようです。

```
 -service: docker
 +services:
 +  - docker
```
これで大丈夫でしょう！

## docker-composeのバージョンが古いよ！

以下のエラーが出て、やっぱりビルドが止まりました。

```
$ docker-compose up -d
Unsupported config option for services service: 'workspace'

The command "docker-compose up -d" failed and exited with 1 during .

Your build has been stopped.
```
なんだこれ？

どうも、Travis上のdocker-composeが古い模様。
なんだそれ。。。

とりあえず、docker-composeのバージョンアップもさっきのtravis公式にあったので適用。

```.travis.yml
 +env:
 +  DOCKER_COMPOSE_VERSION: 1.8.0
 +

 before_install:
 +    - sudo rm /usr/local/bin/docker-compose
 +    - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
 +    - chmod +x docker-compose
 +    - sudo mv docker-compose /usr/local/bin
      - docker-compose up -d
```
これで大丈夫でしょう。

## Dockerのバージョンも古い

```
0.28s$ docker-compose up -d
ERROR: The Docker Engine version is less than the minimum required by Compose. Your current project requires a Docker Engine of version 1.10.0 or greater.

The command "docker-compose up -d" failed and exited with 1 during .

Your build has been stopped.
```
まじかよ。。。
dockerのバージョンを上げなければならない模様。
公式にはdockerのバージョンの上げ方は載っていないけど、sudoが使えるので、普通にバージョンを上げればいいはず。
dockerのバージョン上げの方法をネットで探して、適用。

```.travis.yml
 before_install:
 +    - sudo apt-get update
 +    - sudo apt-get install docker-engine
      - sudo rm /usr/local/bin/docker-compose
```

## ビルドが終わらない

```
$ sudo apt-get install docker-engine
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  libsystemd-journal0
The following NEW packages will be installed:
  libsystemd-journal0
The following packages will be upgraded:
  docker-engine
1 upgraded, 1 newly installed, 0 to remove and 287 not upgraded.
Need to get 19.4 MB of archives.
After this operation, 72.9 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
```
おっと、ここは強制yesのオプションを入れておくべきでしたね

```.travis.yml
-    - sudo apt-get install docker-engine
+    - sudo apt-get install -y docker-engine
```
いやぁ、失敬失敬。
ささ、ビルドしましょう。

```
Configuration file '/etc/default/docker'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** docker (Y/I/N/O/D/Z) [default=N] ? 
```
なんだこれは！？
どうも古い設定ファイルが残っているようで、こいつを残すか消すかを求められている模様。
`-y`オプションつけてもダメポ。
漂浪したうえでようやく見つけたのが次のオプションが`-o Dpkg::Options::="--force-confnew"`。
これをつけることで、ようやく動きました！

```.travis.yml
     - sudo apt-get update
 -    - sudo apt-get install -y docker-engine
 +    - sudo apt-get -y -q -o Dpkg::Options::="--force-confnew" install docker-engine
      - sudo rm /usr/local/bin/docker-compose
```

## 動いたと思ったか！？

ビルドに失敗しました。。

```
Generating optimized class loader
Compiling common classes

The command "docker-compose exec workspace composer install" failed and exited with 129 during .

Your build has been stopped.
```
ステータスコードが129で失敗だとぉ！？
どうやら`docker exec`のステータスコードが何をやってもこのコードが返却される模様。
Docker的には「横道の処理」なので、ちゃんと`docker run`を使わなきゃダメということだろうか。。。

必要な箇所を`run`に置き換えて、

```
$ docker-compose run workspace ./vendor/bin/phpunit
PHPUnit 4.8.26 by Sebastian Bergmann and contributors.

........

Time: 1.17 seconds, Memory: 18.00MB

OK (8 tests, 68 assertions)


The command "docker-compose run workspace ./vendor/bin/phpunit" exited with 0.

Done. Your build exited with 0.
```
やったぜ！

## 最終的な`.travis.yml`

最終的には以下の様な設定に落ち着きました。

```.travis.yml
sudo: required

services:
  - docker

env:
  DOCKER_COMPOSE_VERSION: 1.8.0

before_install:
    - sudo apt-get update
    - sudo apt-get -y -q -o Dpkg::Options::="--force-confnew" install docker-engine
    - sudo rm /usr/local/bin/docker-compose
    - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
    - chmod +x docker-compose
    - sudo mv docker-compose /usr/local/bin
    - docker-compose up -d mysql_test
    - docker-compose run workspace composer install
    - cp .env.example .env
    - docker-compose run workspace php artisan key:generate

script:
    - docker-compose run workspace ./vendor/bin/phpunit
```
途中端折ったりもしているので、詳しく見たいという好事家の方はこちらのリポジトリをどうぞ。
https://github.com/niisan-tokyo/laravel_board

# まとめ

エレガントだったりオシャレだったりっていうのは、その影に泥臭い作業があるものです。

結局何が言いたいかって言うと、「さくっと」「簡単に」「すぐに」「時間が節約できる」といった華麗な文言に惹かれて自分でやってみたら、全然そんなことないやん！ってことがよくあると思います。
しかし、それで諦めずに、ドロドロと検証を続ければ、いつかは達成できるんじゃないかと思います。
そんな感じの日記でした。