OSS版 drone.io でコンテナの中に入ってデバグする方法

**やりたいこと:** 手元ではテストが通るのに、drone ではテストが通らないとなって、試すために一からCIを回す、となるといくら時間があっても足りないので、drone.io がやってるのと同等の操作を行って、直接コンテナに入ってデバグしたい。

## .drone.yml

これを再現したいとする

```yaml
image: "bradrydzewski/ruby:2.0.0"
env:
  - RAILS_ENV=test
git:
  depth: 1
script:
  - bundle install
  - bundle exec rake db:create db:migrate
  - bundle exec rspec
services:
  - mysql
  - redis
```

## サービス(mysql, redis)コンテナの立ち上げ

```
# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
bradrydzewski/ruby    2.0.0               234bd8089bce        19 months ago       3.535 GB
bradrydzewski/base    latest              00fb4af118c1        19 months ago       3.535 GB
bradrydzewski/mysql   5.5                 9add88089b3c        19 months ago       351.3 MB
bradrydzewski/redis   2.8                 9f0d1136eb85        19 months ago       240.9 MB
```

mysql, redis コンテナを立ち上げる。本来はホスト側のポートマッピングはランダムなのだが、mysql, redis のポート番号にそれぞれ 10000 足したポート番号にしてみている。

```
docker run -d -p 13306:3306 bradrydzewski/mysql:5.5
docker run -d -p 16379:6379 bradrydzewski/redis:2.8
```

情報

こんなかんじになるはずなので確認してみてください

注記: `192.268.*.*` は通常環境では `172.17.*.*` になるはず。自分の環境では docker0 のサブネットを 172.17.0.0/16 から 192.168.5.0/24 に変えているため。

```
# docker ps
CONTAINER ID        IMAGE                     COMMAND                CREATED             STATUS              PORTS                     NAMES
b006383aaeb6        bradrydzewski/redis:2.8   "/usr/bin/redis-serv   5 seconds ago       Up 4 seconds        0.0.0.0:16379->6379/tcp   nostalgic_mestorf
3965a5958664        bradrydzewski/mysql:5.5   "/bin/sh -c \"/usr/s   10 seconds ago      Up 9 seconds        0.0.0.0:13306->3306/tcp   adoring_darwin
```

```
# ps -ef | grep docker
root     19335 32520  0 02:11 ?        00:00:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 13306 -container-ip 192.168.5.55 -container-port 3306
root     19436 32520  0 02:12 ?        00:00:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 16379 -container-ip 192.168.5.56 -container-port 6379
```

```
# iptables-save | grep -v "^#"
*nat
:PREROUTING ACCEPT [18:1330]
:INPUT ACCEPT [18:1330]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 192.168.5.0/24 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 192.168.5.55/32 -d 192.168.5.55/32 -p tcp -m tcp --dport 3306 -j MASQUERADE
-A POSTROUTING -s 192.168.5.56/32 -d 192.168.5.56/32 -p tcp -m tcp --dport 6379 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 13306 -j DNAT --to-destination 192.168.5.55:3306
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 16379 -j DNAT --to-destination 192.168.5.56:6379
COMMIT
*filter
:INPUT ACCEPT [151:25433]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [162:21546]
:DOCKER - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 192.168.5.55/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
-A DOCKER -d 192.168.5.56/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 6379 -j ACCEPT
COMMIT
```

## ruby コンテナの立ち上げおよびポートフォワード

コンテナを立ち上げつつ、bash を立ち上げて中に入る。

```
# docker run -i -t bradrydzewski/ruby:2.0.0 /bin/bash
```

drone は socat という独自のコマンドでサービスコンテナのポートを 127.0.0.1 にフォワードしているようなので、それを真似する(docker の --link オプションは使っていないようだ)。IPアドレスは、上述の `ps -ef | grep docker` からわかる。

```
ubuntu$ /usr/bin/socat TCP-LISTEN:3306,fork TCP:192.168.5.55:3306 &
ubuntu$ /usr/bin/socat TCP-LISTEN:6379,fork TCP:192.168.5.57:6379 &
```

これで、127.0.0.1:3306 を指定すると、docker0 を通って、iptables を通って、サービスコンテナにフォワードされる。cf. [Drone - サービスコンテナへのポートフォワーディングをどうしているのか読んでみた](http://qiita.com/udzura/items/221c03e19e5e122a0d54)

## テストを流す

あとは ruby コンテナで、drone の console に出て来るコマンドを真似すればよい。

```
ubuntu$ sudo chown ubuntu:ubuntu /var/cache/drone
ubuntu$ git clone --depth=1 --recursive --branch=master https://github.com/sonots/try_rails4 /var/cache/drone/try_rails4
ubuntu$ /var/cache/drone/try_rails4
ubuntu$ bundle install
ubuntu$ bundle exec rake db:create db:migrate
ubuntu$ bundle exec rspec
```

NOTE: git clone や bundle install に ssh 鍵が必要な場合は、~/.ssh/id_rsa に鍵の登録が必要。drone は [Integrating with Github · drone.io](http://docs.drone.io/github.html) にあるように、drone が内部で秘密鍵を持ち、公開鍵を deploy key として登録することで、git clone できるようにしている。

## おわりに

何か間違えていたり、この方が良い、とかあればつっこみ welcome。private key 周りなんとかしたい。