CircleCI 2.0 で docker-compose を動かすなら、Machine Executor にしないとハマる


# 2017/09/12 追記

Circle CI 2.0 の docker executor が ECR に対応しました。

単純にECRのイメージを使いたいということだけであれば、もうこのページに書かれている machine executor を使う必要はないと思います。

[CircleCI Blog - AWS EC2 Container Registry (ECR) Support](https://circleci.com/blog/aws-ecr-auth-support/)

# 正しく動くものから

最後まで読まないと正解がわからないのはつらいと思うので、正解を最初に書くと、以下のようにすると問題なく動作する。

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
    machine: true
    steps:
      - checkout
      - run:
	  		name: login aws ecr
	    	command: |
	    		login="$(aws ecr get-login)"
             	${login}
      - run:
        	name: docker-compose up
        	command: |
        		 docker-compose -f ./docker-compose.test.yml up -d
    
```

# そんなことしなくても、CircleCI 2.0 って複数 Docker image つかえなかったっけ？

CircleCI 2.0 の設定ファイルでは、docker-compose.yml のように複数の Docker image を指定することができる。

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
  	docker:
	  - image: php:7.1-apache
	  - image: mysql:5.7
      	environment:
			MYSQL_ROOT_PASSWORD: $MYAPP_DATABASE_PASSWORD
	  - image: redis:3.0.5
       
```

<del>だが、指定できるのは、パブリックなリポジトリにあるイメージだけなので、プライベートなリポジトリを使っている場合は、このやりかたはつかえない。(正しく動くものとして、これみよがしに Amazon ECR のログインを書いているのはそのため)</del>

(2017/09/12 追記) 一番上に追記したように docker image の指定に aws_auth という指定が増えて、ECRのイメージをそのまま使えるようになりました。

# 「circleci 2.0 docker-compose」でググるとハマる

「circleci 2.0 docker-compose」でググると、以下のようなページがヒットする。

* [Installing and Using docker-compose](https://circleci.com/docs/2.0/docker-compose/)
* [How to Build a Docker Image on CircleCI 2.0](https://circleci.com/blog/how-to-build-a-docker-image-on-circleci-2-0/)

ここに罠となるキーワードが登場する。`setup_remote_docker` がそれである。

これをつかうことにより、Docker Hub で配布されている Docker image である `docker:17.06.0-ce-git` をつかって、最新の `docker-compose` コマンドを使って、最新の `awscli` コマンドを使って、環境がつくれる！

と思うじゃないないですか。

# `setup_remote_docker` の環境では volume マウントができない

先程の2つのページにあるようなやりかたで、確かに、`docker-compose` コマンドは動く。

だが、 `docker-compose.yml` に記述している、`volumes:` をつかったマウントが動かない。そして、volumenマウントができなかったことに関しては、いっさい警告メッセージもでない。

volume マウントができないと、プライベートなDocker imageを使いつつ、checkout したソースコードをマウントしてテストするということができない。

原因がさっぱりわからず、記述方法に問題があるのか、working directoryが悪いのか等、いろいろ試行錯誤してもさっぱりマウントされない。これによって、ほぼ半日がつぶれました・・・

# 情報がほぼない

根気よくぐぐると以下のようなフォーラムでの回答は見つかる。

* [Docker-compose.yml and volume mounts](https://discuss.circleci.com/t/docker-compose-yml-and-volume-mounts/10043/9)

ここにこういう回答がある

> volume mounts currently only work on the machine executor. You're correct, this does have to do with limitations around a remote Docker Engine. I don't have more details beyond that, though.

ここでようやく、`machine executor` という単語がでてくる。つまり、volume マウントが使いたかったら、`machine executor` を使えということである。

というわけで、プライベートな Docker image を使いつつ、checkout したソースコードをマウントしたかったら、正解な書き方として、最初に示したような形になるわけである。

# そうはいっても、最新の Docker 環境をつかいたい

`docker:17.06.0-ce-git` を使わないと、最新の `docker-compose` の文法がつかえないから、それじゃこまる！という方にも、実は `machine executor` で対応ができる。

* [Writing Jobs with Steps - machine](https://circleci.com/docs/2.0/configuration-reference/#machine)

`machine executor` は以下のような単純な指定方法だと、デフォルトの設定として、`circleci/classic:latest` という、Ubuntu 14.04 + 17.03.0-ce の image で起動する。

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
    machine: true
```

しかし、以下のように指定すると、最新の `17.06.0-ce` 環境で起動する。

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
    machine:
      image: circleci/classic:edge
```

この状態で、pip 経由で `docker-compose` コマンドも最新のものを取ってくれば、最新の Docker 環境で、volume マウントもできるという状態になる。

# 結論

Circle CI 2.0 が、普通の `docker executor` でプライベートイメージをつかえるようになってくれるととてもうれしい。

# 追記

よく見てみれば、[Installing and Using docker-compose](https://circleci.com/docs/2.0/docker-compose/) に以下のように書いてあった・・・

> If you want to use docker compose to manage a multi-container setup, use the machine key in your config.yml file and use docker-compose as you would normally. Note: There is an overhead for provisioning a machine executor and use of the machine key may require additional fees in a future pricing update.

> The overhead delay with machine is a result of spinning up a private Docker server. In contrast, the docker key runs the executor on a shared Docker server that is already provisioned. To secure your builds, some Docker behavior on this executor is not allowed and restricts your ability to use docker-compose.

> For example, use of volumes is restricted. If you have a docker-compose file that shares local directories with a container, it is possible to do this with the machine key, but not with docker. Even though using docker combined with setup_remote_docker provides a remote engine similar to the one created with docker-machine, volume mounting and port forwarding do not work as expected in this setup.

> This combination is really only intended for users who want to build docker images for deployment and cannot be used for performing volume mounting. See the Building Docker Images for details.

確かに、`docker executor` だと、 volume マウントと ポートフォーワードに制限があるので、`machine executor` 使えと書いてあるなぁ。ドキュメントはちゃんとよまないとダメですね・・・

とはいえ、この方法だと、将来的に追加料金になるかもと書いてあるなぁ。追加料金にする前に、プライベートな Docker image をすんなりつかえるようにしてほしい・・・