Skip to main content

15 posts tagged with "drone"

View All Tags

· 4 min read
Shunsuke Suzuki

Drone v1 では Extension という仕組みが導入されました。

これは文字通り Drone を拡張する仕組みで、仕様に従って作れば自由に Drone を拡張できます。

https://docs.drone.io/extensions/overview/

全てを本体でやるのではなく、拡張する仕組みを提供し、あとはコミュニティに委ねるというのが Drone の一つの方針とも言えると思います。

Extension は非常に面白い仕組みだと思いますが、 Drone を運用する立場からすると中々頭が痛い仕組みな気がしてて、 自分は導入に対し慎重な立場です。 単なる杞憂で済めば良いのですが、その懸念について書きたいと思います。

根本は Drone Extension 固有の問題と言うより、一般的な拡張機構全般に言えることだと思います。 ただし、 Drone Extension は全てのビルドに影響を及ぼす、 CI/CDシステムが動かなくなるとサービスのリリースに影響を及ぼしかねないということからよりリスクの高いものになっています。

  • 本体の drone/drone と比べ、開発は活発ではなく、サードパーティの extension はいつ開発が止まってもおかしくない
  • 本体の drone/drone と比べ、ドキュメントやサポート体制が貧弱だと思われる(drone に関しては https://discourse.drone.io でサポートされているが、サードパーティの extension では難しい)
  • ユーザーからの extension に関する要望を受け付けるようになると、管理者の負担になる
  • extension のクォリティはマチマチであり、例外処理が甘かったり、ちゃんとエラーを吐かないものもあるだろう
  • トラブルシューティングが難しいと思われる
  • extension の仕組み上、extension を必要としないビルドにも影響を及ぼしうる
  • 一度追加し、依存しだすと消すのが難しくなる
  • extension が落ちると全 build に影響するので、耐障害性(冗長化)、モニタリングが必要
  • etc

勿論、上記の懸念点は Extension によって提供される機能とトレードオフであり、 Extension の導入方針は Drone が運用される環境によって大きく依存すると思います。

例えば全員が顔見知りのような小さな組織で特定のサービス専用に Drone を使っていてかつ Drone の運用体制(人員)に十分余裕があるなら 積極的に Extension を導入しても問題ないかもしれません。

一方大きな組織で色々なサービスで同じ Drone を使っていてかつ Drone の運用体制が不十分(人手不足)ならば、 Extension の導入には慎重にならざるを得ないのではないかと思います。

· 2 min read
Shunsuke Suzuki

v0.8 では server - agent 間の通信に gPRC が使われていましたが、 v1 では使われなくなりました。

理由

v1 での通信方法


自分も v0.8 から Drone を運用していて最近 v1 に upgrade しましたが、 v0.8 では gRPC 関連のトラブルが頻発していました。 server のログでは絶えず gRPC 関連のエラーを吐いていましたし、 server - agent 間の TCP connection が切れっぱなしになって戻らくなって agent 数がどんどん減っていったり ビルドが pending のままになったり、色々ありました。

関連する issue はあり、幾つか対策を打ってみたりしましたが、結局解決しませんでした。

それが v1 にアップグレードして gRPC が使われなくなってから解消し、個人的にはとても助かりました。 管理者的にはアップグレードして一番嬉しい点ですね。

· 2 min read
Shunsuke Suzuki

Drone では v1 から冗長な YAML を DRY にする一つの手として、 Jsonnet の利用が推奨されています。 これについては過去のブログでも触れています。

https://techblog.szksh.cloud/drone-jsonnet-generator/

しかし、 v1 の rc の時点では Jsonnet の活用には Jsonnet Extension が必要でした。

https://engineering.linecorp.com/ja/blog/go-oss-ci-cd-platform-drone-1-0-0-rc-1/#title7-1

しかし、 v1 の正式版では Jsonnet Extension がなくても Jsonnet が利用できるようになっています。

まず Drone の管理者側で Drone server に環境変数 DRONE_JSONNET_ENABLED=true を設定する必要があります。

そうしたら、ユーザー側は次のようにすることで jsonnet が使えます。

  1. .drone.yml の代わりに .drone.jsonnet をコミットする (.drone.yml は不要)
  2. 各リポジトリの settings の Main > Configuration で設定ファイルのパスを変更する

こうすることでビルド実行時に自動で Jsonnet が YAML に変換され処理されるようです。

いつから Jsonnet Extension は不要になったのか

v1 の rc ではサポートされてませんでしたが、正式版をリリースするタイミングで Jsonnet Extension が不要になっていたようです。

注意点

  • SaaS https://cloud.drone.io は 2019-08-02 時点で未対応
  • Jsonnet は pipeline が 1 つでも [] で囲い、配列にする必要がある
  • Jsonnet の Imports はサポートしていない

リファレンス

· 3 min read
Shunsuke Suzuki

Jenkins では parameterized build という機能で、ビルド実行時に Web UI からパラメータを指定することができます。

Drone では基本的に Git のイベントをフックして動くので「ビルドを実行時に手動でパラメータを設定する」ということは出来ません。

自分は基本的にできなくても構わないと思っていますが、 こういった機能がないから Drone を使わないという人も中にはいるので、 Drone でもちょっとした工夫でそれっぽいことは出来るんじゃないかと思い、簡単なサンプルを書いてみました。

一応言っておくと、 Jenkins の parameterized build を完全に代替するようなものではありません。

https://github.com/suzuki-shunsuke/example-drone-build-parameter

以下のファイルが必要です。

スクリプトを実行してデプロイします。

$ bash scripts/deploy.sh

するとパラメータを記述するファイルがテンプレートから作成され、エディタで開きます。

https://github.com/suzuki-shunsuke/example-drone-build-parameter/blob/master/scripts/deploy.sh#L12-L17

パラメータを記述し、エディタを閉じます。

するとそのファイルがコミットされ、新しいタグが作成され、コミットとタグがリモートにプッシュされます。

https://github.com/suzuki-shunsuke/example-drone-build-parameter/blob/master/scripts/deploy.sh#L27-L35

Drone でタグをプッシュするイベントをフックしてビルドが実行されます。

https://github.com/suzuki-shunsuke/example-drone-build-parameter/blob/master/.drone.yml#L13-L17

ビルドではコミットされたパラメータの設定ファイルを読み込むことでビルドにパラメータを渡せます。

https://github.com/suzuki-shunsuke/example-drone-build-parameter/blob/master/.drone.yml#L10

こうすることでビルドにパラメータを渡すことができます。 パラメータの設定ファイルはコミットされるので Git で管理できるというのも特徴です。

https://github.com/suzuki-shunsuke/example-drone-build-parameter/blob/master/build_params/2019-07-07T10-04-02JST/params.sh

上記のスクリプトではパラメータの設定ファイルとしてシェルスクリプトで環境変数を定義していますが、 シェルスクリプトである必要性はなく、例えば JSON ファイルを記述してビルドで JSON ファイルを読み込んでもよいし、 パラメータを選択させるようなことがしたければ fzf のようなものを使ってもよいし、 いくらでも改善できます。

以上、簡単な tips でした。

· 5 min read
Shunsuke Suzuki

Drone v0.8 の .drone.yml を v1 の .drone.jsonnet に変換するツールを作ったので紹介します。

https://github.com/suzuki-shunsuke/drone-jsonnet-generator

背景

https://docs.drone.io/user-guide/pipeline/migrating/

Drone は v0.8 から v1 で .drone.yml のフォーマットが大きく変わっています。 Drone v1 ではビルド実行時に自動で変換しているため、v0.8 の .drone.yml でもそのまま動きます(matrix builds も動きます)。

そのため、Drone v0.8 から v1 に移行する際、すぐに .drone.yml を修正しなくても問題ないのですが、 v1 独自の機能が出てきた場合 v0.8 のフォーマットの場合利用できないかもしれませんし、 いつまでも古いままだと気持ち悪いので出来るならフォーマットを変換したいです。

drone-cli ではフォーマットを変換する drone convert というコマンドが提供されています。

ただし、 drone convert は matrix build を multiple pipeline に変換するのですが、 非常に冗長になります。 そのため、jsonnet を利用することが推奨されています。

https://docs.drone.io/user-guide/pipeline/migrating/

The above syntax can be quite verbose if you are testing a large number of variations. To simplify your configuration we recommend using jsonnet.

この .drone.jsonnet の生成は drone convert では出来ないですし、手作業になるのですが、結構面倒です。 v0.8 から v1 でフォーマットが変わってますし、jsonnet に馴染みの薄い人も少なくないでしょう。 移行対象のリポジトリが多い場合、非常に苦行になります。

そこで今回この .drone.jsonnet を生成するツールを開発しました。

使い方

非常にシンプルです。

$ drone-jsonnet-generator gen [--source .drone.yml] [--target .drone.jsonnet] [--stdout]

を実行すると .drone.yml から .drone.jsonnet を生成します。

例えば

---
pipeline:
build:
image: golang:${GO_VERSION}
commands:
- echo hello
services:
database:
image: ${DATABASE}
matrix:
include:
- GO_VERSION: 1.4
DATABASE: mysql:5.5
- GO_VERSION: 1.4
DATABASE: mysql:6.5
- GO_VERSION: 1.3
DATABASE: mysql:5.5

から

local pipeline(GO_VERSION, DATABASE) = {
"kind": "pipeline",
"name": "'GO_VERSION:' + GO_VERSION + ' DATABASE:' + DATABASE",
"platform": {
"arch": "amd64",
"os": "linux"
},
"services": [
{
"image": "${DATABASE}",
"name": "database",
"pull": "default"
}
],
"steps": [
{
"commands": [
"echo hello"
],
"image": "golang:${GO_VERSION}",
"name": "build",
"pull": "default"
}
]
};

local args = [
{
"DATABASE": "mysql:5.5",
"GO_VERSION": "1.4"
},
{
"DATABASE": "mysql:6.5",
"GO_VERSION": "1.4"
},
{
"DATABASE": "mysql:5.5",
"GO_VERSION": "1.3"
}
];

[
pipeline(arg.GO_VERSION, arg.DATABASE) for arg in args
]

残念ながら生成された jsonnet はそのままでは使えません。修正が必要です。 それでも一から .drone.jsonnet を書くよりは圧倒的に効率が良いです。

  • pipeline 中の変数が ${変数名} となっているので直す ("golang:${GO_VERSION}" -> "golang:" + GO_VERSION)
  • pipeline name が " で囲まれてるので取り除く ("'GO_VERSION:' + GO_VERSION + ' DATABASE:' + DATABASE" -> 'GO_VERSION:' + GO_VERSION + ' DATABASE:' + DATABASE)

あと、一部のコードを JSON として生成しているので、jsonnet としては多少綺麗ではない(フィールドが"で囲まれてたりする)ですが、実用上特に問題ないと思います。

ちなみに上の例では matrix build の include が使われていますが、使っていない場合にも対応してますし、 include が使われていない場合、若干生成されるコードのテンプレートが違います。

なお、今回のツールの対象になる .drone.yml は matrix build を使っているのが前提になります。 matrix build が使われていないとエラーを返します。 matrix build を使っていないのであれば jsonnet を使う必要性が弱いですし、 drone convert で変換すれば良い気がします。

以上、自作のOSSの紹介でした。 Drone v0.8 から v1 への移行で困っている人は是非使ってみてください。 快適な Drone ライフを。

· 3 min read
Shunsuke Suzuki

久しぶりに Drone plugin を作ったので紹介します。

https://www.github.com/suzuki-shunsuke/drone-plugin-jsonnet-check

.drone.jsonnet から .drone.yml を生成していて、両方を Git で管理している場合に、 .drone.jsonnet と .drone.yml の状態が一致しているかテストするための plugin です。

Drone v1 では matrix builds が廃止され、multiple pipeline が導入されました。 matrix builds を drone convert コマンドで multiple pipeline に変換すると、pipeline の数が多いほど冗長でメンテナンス性が悪くなります。 そこで公式では jsonnet で記述して .drone.yml に変換する方法が推奨されています。

https://docs.drone.io/user-guide/pipeline/migrating/

To simplify your configuration we recommend using jsonnet.

$ drone jsonnet --format --stream

jsonnet から yaml への変換は Jsonnet extension を使うと Drone がビルド実行時に自動で変換してくれるので .drone.yml を管理する必要はなくなりますが、 使っていない場合、 .drone.jsonnet と .drone.yml を Git で管理し、自前で変換してコミットする必要があります。 この作業をなにかしら自動化しないと .drone.jsonnet と .drone.yml に不整合が生じることもあり得ると思います。

  • .drone.jsonnet を更新したけど .drone.yml を更新し忘れる
  • .drone.yml を直接更新してしまった

そこで CI で不整合が生じていないかテストするための plugin を作りました。

最初は plugin ではなく、ただのサンプルコードとして公開しました。

https://github.com/suzuki-shunsuke/drone-jsonnet-convert-test

しかし、折角なので plugin にしました。

やっていることは単純で、 .drone.jsonnet から YAML を生成し、 .drone.yml と diff を取っているだけです。

使い方は README を見れば分かると思いますが、

drone jsonnet コマンドのオプションを plugin のパラメータとして渡せます。

{
kind: "pipeline",
name: "test",
steps: [
{
name: "test .drone.yml",
image: "suzukishunsuke/jsonnet-check:v1.1.1-v0.1.0",
settings: {
format: true,
},
},
],
}
$ drone exec
[test .drone.yml:0] + drone jsonnet --format --target /tmp/.drone.yml
[test .drone.yml:1] + diff .drone.yml /tmp/.drone.yml
[test .drone.yml:2] --- .drone.yml
[test .drone.yml:3] +++ /tmp/.drone.yml
[test .drone.yml:4] @@ -12,5 +12,4 @@
[test .drone.yml:5] settings:
[test .drone.yml:6] format: true
[test .drone.yml:7]
[test .drone.yml:8] -
[test .drone.yml:9] ...
2019/06/01 00:33:27 test .drone.yml : exit code 1

シェルスクリプトで実装しました。 テストでは bats を使っています。

以上、簡単ですが、自作 Drone plugin の紹介でした。

· 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 を使っているからです。