やりたいこと: 手元ではテストが通るのに、drone ではテストが通らないとなって、試すために一からCIを回す、となるといくら時間があっても足りないので、drone.io がやってるのと同等の操作を行って、直接コンテナに入ってデバグしたい。
.drone.yml
これを再現したいとする
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 - サービスコンテナへのポートフォワーディングをどうしているのか読んでみた
テストを流す
あとは 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 にあるように、drone が内部で秘密鍵を持ち、公開鍵を deploy key として登録することで、git clone できるようにしている。
おわりに
何か間違えていたり、この方が良い、とかあればつっこみ welcome。private key 周りなんとかしたい。