Skip to main content

· 2 min read
Shunsuke Suzuki

travis ci と circle ci の無償SaaS 版を比較しています。

OSS の CI では travis ci がよく使われる印象がありますが、 場合によっては circle CI に移行するとCIの時間が大幅に短くなったりして良いと思います。 ただし、複数バージョンで並列にテストしたい場合、circle ci の無償planだと並列に実行できないため、 travis でやったほうが速いかもしれません。

Circle CI の良いところ

  • 好きな Docker Image が使える
  • ローカルでテストが出来る
  • Pending 時間が travis ci に比べて短い気がする(主観)
  • private repository の CI も出来る

好きな Docker Image が使えるのが大きいですね。 予め CI に必要なツールをインストールした Image を用意しておくことで大幅に高速化出来ますし、 ツールがインストールできなかったりバージョンが変わってしまったりするトラブルも避けられます。 同じImageを使ってローカルでテストできるのでローカルでの検証もしやすいです。

自分の場合 Golang のツールの CI用に Docker Image を用意しています。

https://hub.docker.com/r/suzukishunsuke/go-ci/

· One min read
Shunsuke Suzuki

drone OSS 0.8.5 で検証しています。

https://drone.io/https://www.metabase.com/ の話です。

drone の利用状況を可視化したかったので、 drone の DB(MySQL) のデータを metabase で可視化しました。

どんなグラフを作ったのか

いざグラフを作成するとなると、何を作ったらいいのか迷いましたが、以下のようなものをとりあえず作ってみました。

  • ユーザー数
  • 有効化されたリポジトリ数
  • buildの多いリポジトリ
  • buildをよく実行しているユーザー
  • ビルド時間の分布
  • build event の割合(push, tag, pull request, deployment)
  • リポジトリのsecretsの数の分布

· 4 min read
Shunsuke Suzuki

drone OSS 0.8.5 で検証しています。

https://drone.io/https://portainer.io/ の話です。

drone はかなり安定したシステムだと思いますが、 ユーザーが好きなイメージで好きなコマンドを実行できる以上、トラブルが起こることはあります。

その結果、 特定の build がタイムアウトにならずに延々と実行され続けるなんてことがあります。

その場合、

  1. どのノードのどのコンテナでトラブルが起きているのか
  2. そのコンテナで何が起こっているのか

というのを知りたいのですが、 drone にはそういった管理機能はありません。

そこで 複数のサーバで実行されている Docker コンテナを管理できるツールはないかと探したところ、 portainer が良さそうだったので導入しました。

portainer を使うと複数のサーバのコンテナを一覧で見ることが出来、 コンテナを操作(削除、停止、再起動etc)出来ます。 コンテナのログや簡単なメトリックス(CPU, memory, network usage) が見れます。 コンテナだけでなく、network や volume, image といったリソースも管理できます。

portainer の導入

公式ドキュメントに書いてありますが、 swarm cluster を構築してそこにデプロイすればよいです。

困っていること

毎回検索で絞り込みしないといけない

検索で絞り込んだ後に特定のコンテナの詳細画面飛んだ後一覧に戻ると 検索がクリアされているのでもう一度検索しないといけないのが面倒です。

もう少し高度な検索がしたい

自由入力の検索ボックスが1つあるだけで、特にクエリが書けるわけでもなさそうなので、 もう少し高度な検索がしたいです。 例えば Created At で 1時間以上前に特定のノードで作られたコンテナの一覧とか。

docker API でエラーが出て、コンテナを操作できない

これは多分不具合とかではなく自分の設定が良くないのだと思います。 この辺の issue が関係してそうですが、まだ解消できていません。

http error: Unable to proxy the request via the Docker socket (err=context canceled) (code=500)
cron error: endpoint snapshot error (endpoint=primary, URL=tcp://tasks.agent:9001) (err=Cannot connect to the Docker daemon at tcp://tasks.agent:9001. Is the docker daemon running?)
http error: Unable to execute cluster operation (err=Get https://192.160.0.16:9001/volumes: net/http: request canceled (Client.Timeout exceeded while awaiting headers)) (code=500)

· One min read
Shunsuke Suzuki

drone で非rootユーザーで実行されるDocker Imageを使おうとするとbuildに失敗します。

/bin/sh: 3: cannot create /root/.netrc: Permission denied

これについては drone の開発者が回答しています。

結論を言うと、 他のイメージを使うか、 rootで実行されるようにイメージを修正する必要がありそうです。

· One min read
Shunsuke Suzuki

drone 0.8.5 で検証しています。

tag 名による判定方法はドキュメントには書いてないので書いておきます。

when:
ref: refs/tags/foo-* # タグ名が foo-* ならステップを実行

グロブ * には / は含まれないことには注意してください。

上記の例だと、 tag foo/bar/0.1.0 はマッチしません。 これは Go の filepath.Match を使っているからです。

· One min read
Shunsuke Suzuki

恐らく公式ドキュメントに説明がない気がするので書いておきます。 と言っても、以下のissueに全部書いてありますが。

https://github.com/drone/drone/issues/2042

droneの web ui からリポジトリごとに設定できます。 そのリポジトリが誰に見えるかの設定です。

  • public: ログインしていなくても誰でも見れる(publicリポジトリのデフォルト)
  • private: リポジトリにアクセスできる人しか見れない(privateリポジトリのデフォルト)
  • internal: ログインしていれば誰でも見れる

· 2 min read
Shunsuke Suzuki

drone 0.8.5 で検証しています。

matrix:
ZOO:
- 1
- 2
- 3
- 4
FOO:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
BAR:
- 1
- 2

上記の場合、本来 4 8 2 = 64 個実行されるはずのmatrix builds が27個しか実行されなかったのでソースコードを確認したところ、 27個しか実行されないようにハードコードされていました。

関係ある部分だけ抽出すると以下のような感じになります。

limitAxis = 25

axisList := []Axis{}
for p := 0; p < perm; p++ {
axisList = append(axisList, axis)
if p > limitAxis {
break
}
}

制限をかけるのは仕方ないですが、 エラーも warning もなく正常終了し、でもよく見ると 27 個しか実行されていないので ユーザーとしては混乱しますね。 build の結果の画面の上の方に warning があると嬉しいです。

· One min read
Shunsuke Suzuki

drone 0.8.5 で検証しています。

drone の build の タイムアウトの設定はリポジトリの settings から変更できそうですが、 実は drone の admin しか変更できません。

ブラウザのデベロッパーツールを使うと、この Timeout の設定を変更した際に

PATCH /api/repos/:owner/:name

にリクエストが飛んでいるので、そこからコードを追いかけると分かります。

· 4 min read
Shunsuke Suzuki

drone の build における GitHub (GitHub前提で書きますが、GitHub以外でも同じだと思います) の認証の話(どうやって認証しているか)について書いておこうと思います。 drone の build は clone step で対象のリポジトリを GitHub から clone してきています。 この際に何かしらの方法で認証しているはずです。

結論を言うと、

あるリポジトリAのbuildでは、 リポジトリAの drone連携を有効化したユーザー Bの access token を .netrc に書き込んで認証しています。 よってユーザーBにcloneする権限があるリポジトリはcloneできるし、 ユーザーBにcloneする権限がないリポジトリはcloneできません。 つまり、 誰が連携を有効化するかが重要 になります(これについては後述します)。 なお、drone連携の有効化はそのリポジトリのowner以上でないと出来ません。

drone上でリポジトリの連携を有効化すると、 リポジトリのHookが作成されます。 リポジトリの settings > Hooks から確認できます。 この Hook の Payload URL を見ると access_token クエリがあると思います。 JWTのようですね。これはリポジトリの連携を有効化したユーザーのtokenです。

このtokenが GitHub から drone への webhook のパラメータとして送られてくるので、 drone 側で認証し、認証したユーザーのGitHub のaccess token を取得し、 build 時にコンテナの /root/.netrc に書き込むようです。

.netrcに書き込まれているのは試しに個人の private repository で .netrc をcatしてみればわかります。 他人も見えるrepositoryでcatすると悪用されかねないので気をつけましょう。

pipeline:
netrc:
image: alpine:3.6
commands:
- cat ~/.netrc
+ cat ~/.netrc
machine gihub.com
login **************
password x-oauth-basic

cloneステップ以外での .netrcの活用

.netrc のおかげで難しいこと考えずに clone 出来ているわけですが、この .netrc は当然 clone ステップ以外でも使えます。 例えば private repository の ansible role の install です。

roles.yml

- src: https://github.com/<owner>/<repo>
name: foo.bar
scm: git

.drone.yml

commands:
- ansible-galaxy install -r roles.yml

誰が連携を有効化するべきか

結論を言うと、ベストな方法は分かりません。

連携を有効化した人が退職してしまったり、organizationから抜けてしまった場合、急にビルドが失敗するリスクがあります。 理想を言えば特定の個人のアカウントで連携するのではなく、連携用のアカウントを用意するのが良いのかもしれませんが、 それはそれで運用が難しいかもしれません。

drone API ないし CLI で有効化は出来るので、CIで連携を自動化することは可能だと思います。

自分のところではまだそこまでやってなく、個人で有効化してしまっているのですが、 自動化したらまた記事にでもしたいと思います。

· 3 min read
Shunsuke Suzuki

drone は同じ pipeline の step 間で同じ workspace を docker の volume としてマウントすることで workspace を共有します。

http://docs.drone.io/workspace/

circle ci はデフォルトで job 間で workspace を共有しません。 persist_to_workspace を指定することで共有する事ができます。

https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs

circle ci の場合は volume を共有するのではなく、指定したディレクトリを archive し、次の job で展開することでファイルを共有するようです。

この違いには一長一短があります。

circle ci の場合は archive, unarchive する分、volume 共有に比べて時間がかかります。

そのため、下手に job を分けるより一つの job で処理したほうが処理時間が短くなる場合がありますが、 build や test といった処理は出来れば別の job として実行したいでしょうし、それでは workflow が使えません。

ただし、共有するパスは自由に選べるので必要最小限に抑えることで時間を短縮できます。

また、circle ci の場合は archive するパス及び展開先のパスを自由に選べるので自由度が高いです。 drone の場合、 workspace 以外のファイルを共有できません。

また、drone の場合 volume を共有するので同じ pipeline の step は同じノードで実行されるという制約がありますが、 circle ci の場合、別のノードでの実行が可能です。 drone の group を使って並列に実行する場合、複数のノードに分散できませんが、 circle ci の場合分散できるのでよりスケールしやすいと言えるでしょう。

結局どっちのほうがいいのか

一長一短があると言ったとおり、一概にどっちが良いとは言えませんが、個人的には drone のやり方のほうが直感的だし、 何より速いので好きです。同じ pipeline の処理を複数のノードに分散させたいことって個人的にはあまりありません。