Puppet
docker
drone.io
DockerDay 11

OSS版 Drone.io を社内で使い始めてる話

More than 3 years have passed since last update.

標記の通りで、Docker tips直球じゃなかったりしますが、コアにDockerがいるツールではあるよと言うことで。

どんな感じで運用しているかの話をしてお茶を濁しつつDocker話題を交えていきます。


インストール

Puppetのマニフェストをきっちり書いて、後述するようにそのマニフェストをdrone自身にCIさせている。

DockerのPuppetモジュールとして garethr-docker と言うのを使っている。Droneのマニフェストはインストール手順を見て自分で書いた。

インスフトール手順をレシピに落とすのはそこまで難しくなかった。Puppetが苦手なら、ChefなりAnsibleなりで一度一通り書いておくと安心感があると思う。


監視

munin で雑にやっている。せっかくDockerが入るので普通にmuninのイメージを引っ張って監視が設定できる。便利。あ、 udzura/munin-master はぼくの作ったイメージです。。

docker pull udzura/munin-master

docker run -d -p 8080:80 -e "NODES=dokku001.local:192.168.46.110" udzura/munin-master

これだとデフォルトのプラグインしかないため、後述するようにfd周りが怪しいからそこを監視するプラグインを書く(もしくは同僚にもらう)必要がある...。

ちなみに上で紹介したPuppetのDockerモジュールがめっちゃ便利で、こんな感じのマニフェストを書けば上と同等のコンテナを立ち上げてくれる。

package { 'munin-node': }

docker::image { 'udzura/munin-master': }

docker::run { 'drone001_munin001':
image => 'udzura/munin-master',
ports => ['8080:80'],
volumes => ['/etc/localtime:/etc/localtime:ro', '/var/munin-data:/var/lib/munin'],
# docker0 ネットワークの ip address が facter で取れる
# これはコンテナから見たDockerホストのIPとなる
env => ["NODES=drone001.local:${ipaddress_docker0}"],
}


カスタムイメージについて

Droneの醍醐味はテスト用のDockerイメージを自作できることだと思う。

ひとまずこっちでフォークしてカスタムイメージを作る運用をしている。

Droneのイメージ作りにはいくつかコツがある:



  • bradrydzewski/base もしくはそれをベースにした bradrydzewski/* からつくった方が何かと便利


  • bradrydzewski/base には、ここに書いてある通りgccやらmake、PythonにRubyと言った基本的なツールや言語が既に入っている。言語をまたいで何かする場合も便利

  • Droneのルールとして、イメージ名が drone/* または bradrydzewski/* で始まっているとUSER ubuntuでコマンドが実行される。Dockerfileでもsudoなど適宜する必要がある。

Ruby 2.1.5 のイメージとかは公式にまだ無いみたいで、そういうのは自分でビルドしてある。

将来は、Dockerfileリポジトリを社内GH:Eとかに置いて、プルリクがマージされたらDroneのホストでビルドして(それもDroneでやる!)すぐ使えるようになる、みたいなのを構築しようと思っている。


Docker in Docker なテストを作る


Dockerfile

# see https://registry.hub.docker.com/u/igneoussystems/docker-client/dockerfile/

FROM bradrydzewski/go:1.3
MAINTAINER udzura@udzura.jp

RUN sudo apt-get install -y aufs-tools ca-certificates curl git xz-utils

ENV DOCKER_VERSION 1.3.1
RUN sudo curl -SL https://get.docker.io/builds/Linux/x86_64/docker-$DOCKER_VERSION -o /usr/bin/docker \
&& sudo chmod +x /usr/bin/docker

# Total hack since this is typically a client looking at the host
ENV DOCKER_HOST tcp://172.17.42.1:2375


こう言うDockerfileで、drone/docker-in-docker:1.3.1 という名前のイメージを作る。なお、後述するようにGoのサービスを動かしてたりするマニフェストのテストなので、bradrydzewski/go:1.3をベースにして一緒にGoのテストも動かしたりする。



  • docker クライアントコマンドはバイナリをダウンロードすれば終わるので便利


  • ENV DOCKER_HOST tcp://172.17.42.1:2375 はかなり雑なハックだが大丈夫なのだ...。

このイメージから、DroneをホストしているDockerのコンテナを操作できる。


.drone.yml

image: drone/docker-in-docker:1.3.1

env:
- CONTAINER_NAME=drone-puppet_${DRONE_COMMIT:0:8}
- IMAGE_NAME=drone-puppet

script:
- docker version
- docker build -t $IMAGE_NAME .
- docker run --name=$CONTAINER_NAME --cap-add=SYS_ADMIN -d $IMAGE_NAME
- sleep 3
- docker exec $CONTAINER_NAME /bin/bash -c 'cd /var/puppet && librarian-puppet install --path=vendor/modules'
- docker exec $CONTAINER_NAME /bin/bash -c 'cd /var/puppet && puppet apply --modulepath=modules:roles:vendor/modules manifests/drone.pp; echo $? > /tmp/puppet-result'
- test $(docker exec $CONTAINER_NAME /bin/cat /tmp/puppet-result) -eq "0"
- docker stop $CONTAINER_NAME
- docker rm $CONTAINER_NAME || true
- docker rmi $IMAGE_NAME || true



  • プロジェクトに ADD . /var/puppet する感じのDockerfileを置いて、ビルド。

  • 作ったイメージを立ち上げ。


  • docker execpuppet apply し、

  • Serverspec も走らせる。

そうそう、--cap-add=SYS_ADMIN するとDockerコンテナ内でDockerをインストールできる。インストールはね(aufsかcgroups周りのパッケージインストールで必要だったのだ。詳細は忘れちゃった...)。

なお、 docker exec は 1.3.1 の段階では失敗しても0で終わるのでハックしている... 以前Qiitaに書いた

あと、まれに docker rm が失敗したりする(なんでだろう感はある...)が、それはテストの失敗ではないので || true してビルド結果に反映しないようにしている。

ともかく言いたいのは、こんなDocker in Dockerなテストでも大丈夫なので、たいてい何でもできるであろうと言うことであった。


Ikachanと連携する

弊社、IRCのハードユーザで、Ikachanと連携できると便利だったためなんとかした。

具体的には、Webhookの内容をIkachanにプロクシする感じのWebサーバをGoで書いて立ち上げておく。

Webhookからはこういう感じのパラメータが渡るので、Go側で構造体にマップし、メッセージを構築して、おもむろにIkachanのURLを叩くだけの人を作り、upstartで立ち上げてホストする。

{

"owner": {
"remote": "enterprise.github.com",
"login": "udzura",
"name": "Uchio KONDO",
"email": "udzura@udzura.jp",
"gravatar": "ccb4e184486440f53806a21a97c2xxxx",
"admin": true,
"active": true,
"syncing": false,
"created_at": 1415183037,
"updated_at": 1415239960,
"synced_at": 1415183063
},
"repository": {
"remote": "enterprise.github.com",
"host": "ghe.tokyo.pb",
"owner": "udzura",
"name": "sample",
"url": "http://ghe.******/udzura/sample",
"clone_url": "git@ghe.******:udzura/sample.git",
"git_url": "git://ghe.******/udzura/sample.git",
"ssh_url": "git@ghe.******:udzura/sample.git",
"active": true,
"private": false,
"privileged": false,
"post_commits": true,
"pull_requests": true,
"timeout": 3600,
"created_at": 1415183045,
"updated_at": 1415183051
},
"commit": {
"id": 2,
"status": "Success",
"started_at": 1415260461,
"finished_at": 1415260502,
"duration": 41,
"sha": "e88332a0256d997787fcf73311380d863700e265",
"branch": "sample-hook",
"pull_request": "",
"author": "udzura@udzura.jp",
"gravatar": "1855706b918a88ed1401439986cbxxxx",
"timestamp": "2014-11-06T16:53:12+09:00",
"message": "Add webhook sample",
"created_at": 1415260461,
"updated_at": 1415260502
}
}

Dockerの話ではないけど、Goでサーバ書いてupstartで雑にデーモンにしてPuppetの雑なレシピを書くのは凄く楽で最高の体験だった。

.drone.yml はこんな感じになる。以下の設定で、 #sample と言うチャンネルに失敗と成功寺に通知してくれる。

notify:

webhook:
on_success: true
on_failure: true
urls:
- http://localhost:9292/channels/sample

IRCは普通に対応していると書かれているがSSL非対応のようだった。なんでこんな方法で。そのうちSSL対応のプルリク等送れると良いが...。もっとGo頑張ろう...。

あ、ちなみにDrone本体は、SlackとかHipchatとかgitterとか普通に対応してる んで、その辺のユーザさんは安心して良さそう。


[FIXED] 困ったこと: fdをめっちゃ沢山掴んでulimitを超えることがあった

運用していて、意外と安定してるな〜と言う感想を持っているが、一つ明らかなバグがあった。

要するに、dronedプロセスが何かしらの原因でfdを掴みっぱなしになっているようで、それがどんどん増えていって最後は too many open files になってしまう。

Droneの起動スクリプトをこんな感じにして、なおかつ定期的に再起動して今はしのいでいる感じ。


drone.conf

start on (filesystem and net-device-up)

chdir /var/lib/drone
console log

script
ulimit -n 65536 # 雑...
/usr/local/bin/droned --config=/etc/drone/drone.toml
end script


Issueの通り認識済のバグなので直る日は来ると思う、 けど11月から反応が無いぞい... →FIXされました。素晴らしい。


——と言う感じで、Drone.ioのインハウス運用は予想以上に使えてるなーと言う感想を持っている。あと普通に運用してるだけでDockerの勉強になる...。

是非ユーザが増えて情報も増えると良い感じだなと思った。

明日は @hanhan1978 さんです!