Go製OSS CI/CDプラットフォーム drone 1.0.0-rc.1 の新機能・変更点

この記事はLINE Advent Calendar2018の8日目の記事です。

はじめまして。LINEのIT戦略室という部署で社内システムの開発・運用を担当しております、suzuki-shunsuke です。 自分がオンプレミスで運用している OSSバージョンの drone ci ですが、遂に 1.0.0 の rc が出ました。

なので 1.0.0 になって何が変わるのかということをドキュメントを読んだり実際にインストールしたりして調べてみました。

また、2018/11/21 に Drone Cloud という無料で drone が使える SaaS がリリースされましたのでそれについても紹介します。

drone って何?という方は こちら を御覧ください。

なお、当記事中で「現在」と言った場合、特に断りがなければ執筆時点の2018/11/12 を指します。 また、リモートのGitリポジトリは特に断りがなければGitHubとします。

無料で使える SaaS “Drone Cloud”がリリースされました

本記事の本題は drone-1.0.0-rc.1 の新機能・変更点の紹介・検証なので、あくまでおまけ的な内容なのですが、 極めて大きなニュースなので最初に持ってきました。

2018/11/21 に無料で drone が使える SaaS “Drone Cloud” がリリースされました。

軽く触ったところ、drone のバージョンは 0.8.x ではなく、1.0.x のようです。 https://cloud.drone.io/ にアクセスして OAuth認証すると直ぐに使えます。 なので 1.0.x を直ぐに触ってみたいという方はこちらを使ってみるのが早そうです。

無料でも使える他の SaaS (travis ci, CircleCI, etc) と比べて1つ大きな点として、services があるかと思います。 redis や mysql といった DB を使ったテストなどが可能です。 Drone Cloudでも使えることを確認しました

サービスに関するドキュメントは見当たらず、どういった制限があるのかとかは分かりませんし、 いつまで無料で使えるのかも分かりませんが、 これを機により一層 drone が普及するのではないかとワクワクしています。

以上、冒頭から横道にそれましたが、以降本題に戻ります。

0.8.x のドキュメントのURLの変更

1.0.0-rc.1 のリリースに伴い、公式ドキュメントが大きく変わり、ドキュメントへのリンクが色々壊れてしまっています。0.8.x のドキュメントは https://0-8-0.docs.drone.io/ に移動したようです。 昔の drone に関するドキュメントを読んでいると壊れたリンクに遭遇することがあると思います。

その代り、1.0.0 のドキュメントだと今までなかった YAMLのリファレンスがあったりして良いですね。

リリースノート

この章ではリリースノートに沿って新機能・変更点の概要を紹介します。

0.8.x から 1.0.0 へのアップグレード

https://docs.drone.io/releases/1.0.0-rc.1/#upgrading-important

かつて自分が 0.8.2 から 0.8.5 にアップグレードした際には、初回起動時に自動でDBのマイグレーションが実行されました。 0.8.xから1.0.0へのアップグレードではDBに互換性のない変更が入り、現時点では自動でマイグレーションはしません。 マイグレーションツールを 2018/11/16 かそれより前に出すことを計画しているようです。 マイグレーションツールが従来どおり自動で実行されるかはちょっと分かりません。

Notable Features

https://docs.drone.io/releases/1.0.0-rc.1/#notable-features

以下の様々な機能が増えています。

詳細は別の節で書きます。

Breaking Changes

https://docs.drone.io/releases/1.0.0-rc.1/#breaking-changes

  • drone server と agent の設定のパラメータ名の変更
  • REST APIの変更(主にフィールド名の変更)
  • Global Secrets のサポートを外部プラグインに移行
  • Global Registry credentials のサポートを外部プラグインに移行
  • Vault Secrets のサポートを外部プラグインに移行

Global Secrets, Global Registry credentials, Vault Secrets といった元々 Enterprise バージョンでないと使えなかった機能が外部プラグインになっています。OSS版でも使えそうです。

https://docs.drone.io/extend/

OSS版を使っている身としてはありがたい話です。

APIの変更は既にAPIが色々な所で使われていたりすると大変そうですね。

Breaking Yaml Changes

https://docs.drone.io/releases/1.0.0-rc.1/#breaking-yaml-changes

0.8.xから 1.0.0 では .drone.yml のシンタクスに大きな変更が入っていますが、後方互換性は保たれています。 つまり0.8.xで動いていた .drone.yml はそのまま 1.0.0 でも動きます。素晴らしいですね。 ただし matrix builds は除くようです。弊社では matrix builds を使ってビルドの高速化がよく行われているのでこれはネックになりそうです。

Known Issues

https://docs.drone.io/releases/1.0.0-rc.1/#known-issues

drone は GitHub の Deployment webhookをサポートしていません。 drone には deployment という event がありますが、これは GitHubの deployment とは別物です。 GitHub の deployment では payload というパラメータで任意のパラメータを渡すことが出来ますが、 drone の deployment ではそういったことは出来ません。

https://developer.github.com/v3/repos/deployments/#parameters-1

ここまで新機能・変更点の概要を紹介しましたので、 ここからは各新機能・変更点についてより詳しく説明します。

Windows サポートについて

https://blog.drone.io/drone-cloud-native-ci-cd-windows-containers/

Now Windows developers have the ability to run CI/CD pipelines on Windows, inside Windows containers using Drone.io, providing developers a cloud native way to build and test code.

windows コンテナを使ってビルドが実行できるようです。 自分はwindows コンテナというものを知らなかったのですが、windows プログラムを実行できるコンテナだそうです。

http://www.atmarkit.co.jp/ait/articles/1702/02/news039.html

あまり弊社的には需要がない気もしますが、良い話ですね。

cronスケジューリング

cronスケジューリングのサポートも大きな話ですね。 JenkinsやCircleCIにはある機能ですが、drone にはありませんでした。

ただ使い方がドキュメントに書いてなかったので、forum で教えてもらいました。

https://discourse.drone.io/t/how-to-use-cron-scheduling-in-drone-1-0-0-rc-1/2999

どうやら実行される時間間隔は指定できるものの実行される時刻を指定することは難しいようです。 また、時間間隔にしても、drone server のコンテナを再起動、再作成したりするとずれてしまうので厳密にはなりません。

この辺の仕様が問題になる場合、スケジューリングは drone 以外の仕組みを考えたほうが良さそうです。

因みにどうしても 0.8.x でbuildの定期実行をしたい場合、Jenkins などでジョブを定期実行し、 drone の build start APIを叩くか、tagやコミットをpush してその event を drone で hook するかすれば、それに近いことは出来ます。

multi machine pipeline

複数のマシンで build を実行してビルド時間を短縮できる機能ですね。 元々あった matrix builds に代わるもので、matrix builds は廃止の方向になりそうです(ただし1.0.0では後方互換性を維持しています)。

同じYAMLの動作を環境変数によって変えるmatrix builds と違い、全く別の YAMLとして記述します。 depends_on によって pipeline の依存関係を定義したり、 triggers によって pipeline を実行する条件を定義するようです。

とここで気になることが書いてあります。

Please be warned that most projects do not require multi-machine pipelines. You should exhaust every other option, including parallel pipeline steps and more powerful machines. Multi-machine pipelines will increase complexity, and could actually increase execution times when improperly used.

  • 多くのプロジェクトでは multi machine pipeline は必要ない
  • parallel pipeline steps やマシンのスケールアップなど、他の選択肢をまずは試すべき
  • multi machine pipeline は複雑であり、使い方を間違えると遅くなる

弊社的には受けの良さそうな機能ですが、迂闊に使ってはいけないようです。

確かに下手に depends_on や triggers を導入すると複雑で理解が難しくなり、droneのシンプルさが損なわれてしまいそうですね。

extension

https://docs.drone.io/extend/

drone extension は、システムにインストールしなくてもユーザーが自由に使える drone plugin とは違い、 drone server や drone agent のように Docker コンテナとして起動しておき、server や agent と通信して機能を提供します。

extension として切り離すことで drone server や agent の肥大化を避けるデザインだと思います。

現状以下の4つの extension があります。

  • Jsonnet extension
  • Kubernetes Secrets
  • AWS Secrets Manager: これは今回は割愛
  • Vault Secrets

AWS 以外の3つのextension について簡単に紹介します。

jsonnet extension

drone のビルドの設定は従来 .drone.yml をリポジトリのルートディレクトリに置いておくものですが、 jsonnet extension を使うと、リポジトリ中のjsonnetファイルからビルド実行時に動的に設定ファイルを生成してくれるようです。

jsonnetは使ったことないのですが、 JSONやYAMLといった設定ファイルのテンプレート言語だそうです。

https://jsonnet.org/

drone server と jsonnet extension 間でHTTPで通信します。 jsonnet extension を動かすには

  1. GitHub Token
  2. Shared Secret

の2つが必要です。GitHub Tokenは jsonnet extension が GitHub から jsonnet ファイルを取得するのに必要です。 Shared Secret はdrone serverとjsonnet extension 間の通信の暗号化及び認証のために使われます。

jsonnet extension は GitHub のみサポートしており、GitLabやBitBucket のようなGitHub以外のシステムはサポートしていません。 これは仕様です。

GitHub Token が必要になるのがネックですね。 何かしらのユーザーの personal access token を発行することになるのですが、そのユーザーが fetch する権限のないリポジトリでは jsonnet が使えません。

This token is used to fetch the jsonnet configuration file from the repository. This token must therefore have sufficient permission to do so.

専用のユーザーを用意して、jsonnet extension を使いたければそのユーザーに fetch する権限を付与するという運用になりそうです。

インストール方法はドキュメントの通りですが、Github Enterprise を使っている場合 jsonnet extension のパラメータ GITHUB_SERVER で GitHub Enterprise の API のエンドポイントを指定する必要があります(指定しないと https://api.github.com になってしまいます)。

https://github.com/drone/drone-jsonnet-config/blob/9e05977b1445c6c8049acf107d126e527ae1bea4/cmd/drone-jsonnet-config/main.go#L23

インストールしましたら、リポジトリ直下に .drone.jsonnet を置きます。 .drone.jsonnet は pipeline の配列である必要があります。

{
  "kind": "pipeline",
  "name": "default",
  "steps": [
    {
      "name": "hello",
      "image": "alpine:3.8",
      "commands": [
        "echo hello"
      ]
    }
  ],
}

だとだめで(パースに失敗して build が実行されませんでした)、

[{
  "kind": "pipeline",
  "name": "default",
  "steps": [
    {
      "name": "hello",
      "image": "alpine:3.8",
      "commands": [
        "echo hello"
      ]
    }
  ],
}]

とする必要があります。

また、現時点ではjsonnet extension を有効にすると全ての repository で jsonnet extension が有効になるようです。 repository settings には有効・無効を切り替えるようなUIはありませんでした。 jsonnet extension が有効だと .drone.yml があっても .drone.jsonnet がないとビルドが実行されません。 一部の複雑な pipeline が必要なリポジトリのみ jsonnet を使いたいと思っても出来ないようです。 そうなると全ての repository で .drone.yml から .drone.jsonnet への変換が必要になりますし、シンプルな pipeline なら YAMLのほうが読みやすいですし(主観)、あまり現実的ではないかなと感じました。

そこで質問してみたところ、回答が返ってきました。

https://discourse.drone.io/t/can-we-make-jsonnet-extensions-enabled-or-disabled-per-repositories/2998/2

そのうち修正されることを期待しましょう。

Kubernetes Secrets

k8s の secret object を drone から参照する extension です。 k8s の API を extension から呼び出すため、extension のコンテナに k8s のクレデンシャルをマウントする必要があります。

# $HOME/.kube/config をマウントして extension を起動
$ docker run \
    --env=SECRET_KEY=558f3eacbfd5928157cbfe34823ab921 \
    --volume=$HOME/.kube/config:/etc/kubernetes/config \
    --publish=3000:3000 \
    drone/kubernetes-secrets

そして .drone.yml で secret を参照します。

kind: pipeline
name: default

steps:
- name:
  image: plugins/docker
  settings:
    repo: octocat/server
    tags: latest
    username:
      from_secret: username
    password:
      from_secret: password

---
kind: secret
external_data:
  username:
    path: docker
    name: username
  password:
    path: docker
    name: password

しかし全ての build であらゆる secret を参照できてはセキュリティ上問題ですね。 そのため、 k8s で secret を作成する際に参照できるリポジトリ及び drone の event を制限できます。

apiVersion: v1
kind: Secret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
metadata:
  name: docker
  annotations:
    # org を octocat に制限
    X-Drone-Repos: octocat/*
    # 複数指定できる
    # X-Drone-Repos: octocat/*,spaceghost/*
    # org ではなく repository を指定できる
    # X-Drone-Repos: octocat/hello-world
    # event を push, tag に制限
    X-Drone-Events: push,tag

Vault Secret

Kubernetes Secret と同様に、Vault の secret を drone の build から参照できるようにする extension です。 使い方もKubernetes Secret とよく似ているので説明は割愛します。 ただ、公式のドキュメントに extension に渡すべきパラメータの説明が書いていない気がするので書いておきます。

https://docs.drone.io/extend/secrets/vault/install/

のサンプル

$ docker run \
    --env=SECRET_KEY=558f3eacbfd5928157cbfe34823ab921 \
    --publish=3000:3000 \
    drone/vault

を見てもアクセス先の vault に関するパラメータを渡していません。 extension のソースコードを見るとドキュメントには書いていない環境変数が確認できます。

https://github.com/drone/drone-vault/blob/374e2b4a5851e6149b67a6bbdd3aa3265cbed5ae/cmd/drone-vault/main.go#L42

VAULT_ADDR などを指定する必要がありそうです。

Signature

https://docs.drone.io/config/signature/

.drone.yml に署名をして改ざんを防ぐことが出来ます。 .drone.ymlが変更された場合、そのリポジトリのadmin権限のある人が承認するまでpipelineの実行はブロックされます。 drone の Web UIのリポジトリのsettingsから有効化出来ます。

やり方は、.drone.ymlに signature リソースを定義し、そこに署名をします。

---
kind: pipeline
name: default

steps:
- name: build
  image: golang
  commands:
  - go build
  - go test

---
kind: signature
hmac: F10E2821BBBEA527EA02200352313BC059445190

...

この署名はリポジトリ固有のものであり、 drone sign コマンドによって生成できます。

$ drone sign octocat/hello-world
F10E2821BBBEA527EA02200352313BC059445190

--save オプションをつけると自動で .drone.ymlに署名がされます。

$ drone sign octocat/hello-world --save

drone fmt コマンド

このコマンドに関するドキュメントは現時点では特に見つからなかったのですが、 .drone.ymlを整形するコマンドです。

.drone.yml のシンタクスの大きな改善

https://docs.drone.io/config/pipeline/migrating/

k8sにインスパイアされ、大きく変更されました。

kind: pipeline
name: default

steps:
- name: build
  image: golang
  commands:
  - go build
  - go test

services:
- name: redis
  image: redis:latest

自分が軽くハマったのは plugin のパラメータを settings に記述するようになった点です。

- name: notify
  image: plugins/slack
  settings:
    room: general
    webhook: https://...

これを次のように書いても syntax error にならず、「なぜかパラメータが渡らない」とハマってしまいました。

- name: notify
  image: plugins/slack
  room: general
  webhook: https://...

drone server と agent の設定のパラメータ名の変更

色々変わっていそうですね。 これはマイグレーションツールが欲しくなります。

自分が 1.0.0-rc.1 をインストール時に気づいたものだけ記載しますが、他にも色々あると思います。

drone server

0.8.x 1.0.0-rc.1
DRONE_GITHUB_URL DRONE_GITHUB_SERVER
DRONE_GITHUB_CLIENT DRONE_GITHUB_CLIENT_ID
DRONE_GITHUB_SECRET DRONE_GITHUB_CLIENT_SECRET
DRONE_SECRET DRONE_RPC_SECRET
DRONE_HOST DRONE_SERVER_HOST
DRONE_GITHUB_PRIVATE_MODE DRONE_GIT_ALWAYS_AUTH

drone agent

0.8.x 1.0.0-rc.1
DRONE_SERVER DRONE_RPC_SERVER
DRONE_SECRET DRONE_RPC_SECRET
DRONE_MAX_PROCS DRONE_RUNNER_CAPACITY

drone 1.0.0-rc.1 をインストールしてみた

ここまで 1.0.0 の新機能・変更点について説明しました。 ここからは drone 1.0.0-rc.1 を(アップグレードではなく)新規にインストールしてみて、 UIの変更点やインストール時にハマった点などについて説明します。

drone server 1台、drone agent 1台の2台構成で構築してみました。

https://docs.drone.io/intro/github/multi-machine/

何枚かスクショを貼ります。 0.8.x からの変更点に着目してコメントを入れています。 リポジトリ名など、画像は一部加工しています。

初回ログイン直後の画面です。同期中です。

ログインエラーになっている画面です。 「Repositories -> login/error」となっているのがわかりますでしょうか? ここは分かりにくいですね。

リポジトリの一覧です。なんとなく見た目がキレイになっていますね。

リポジトリの一覧から各リポジトリの直近の build の結果がわかるようになっています。便利ですね。

リポジトリの設定画面です。1ページに収まっています。

その分 menu はこれ以上ないくらいシンプルになっています。

Repository Hooks が消えていて、 .drone.yml の triggers で設定するようになっています。

---
kind: pipeline
name: default
steps:
- name: hello
  image: alpine:3.8
  commands:
  - echo hello
trigger:
  # tag event のみ build を実行
  event:
  - tag

.drone.yml で条件を定義しないと push や tag イベントで build が走り stepが実行されるようです。 そのまま移行すると今まで実行されなかった build が実行されてしまうという点に置いて互換性は損なわれていますが、 Web UIからの設定がなくなり、.drone.ymlに集約されたことは良いことだと思います

registry, Timeout も見当たりません。

ビルドの結果画面です。キレイですね。

あと restart build すると、表示が新しい build に勝手に切り替わりました。これは便利です。

全体的に見た目がキレイになっています(元々キレイではありますが)。 かつ見た目のシンプルさは維持されていますね。

インストール時にハマった点

drone server と agent の設定のパラメータ名の変更 も参考にしてください。

        • GitHub の OAuth App の Authorization callback URL のパスが /authorize から /login に変わっています
        • drone server の port が 80, 443 固定?
        • MySQLの初回マイグレーションが途中で失敗しました(未解決)
Error 1118: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

https://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

forum 見ても同様の報告はありませんでした。

今回は SQLite を使うことにしました。

        • SQLiteを使う場合、マウントすべきパスが /var/lib/drone から /data に変わっていました
        • GitHubに作られるWebhookのURLが drone server の IP になってしまい、webhookで失敗してました
          • DRONE_SERVER_HOST でIPアドレスを指定していたので、ドメインに修正しました
        • GitHub Enterprise で clone に失敗しました fatal: could not read Username for 'https://<github enterprise のdomain>': No such device or address
          • DRONE_GITHUB_PRIVATE_MODE が DRONE_GIT_ALWAYS_AUTH に変わってました
            • 一度DRONE_GIT_ALWAYS_AUTH が false の状態で有効化したリポジトリは DRONE_GIT_ALWAYS_AUTH を true に切り替えたあとに一旦無効化してもう一度有効化し直す必要があります

まとめ

0.8.x から 1.0.0 での変更点、新機能などを検証しました。 まだ 1.0.0 が production 環境で使えるのは先の話かと思いますが、 UIや .drone.yml が改善されていたりマルチマシンpipeline や clone scheduling などの新機能が追加されたりして 早くアップグレードしたいという気持ちが高まりました。

こちらは Windows サポートの blog ですが、 これを見ても drone の本気度のようなものが感じられますね。

なにより長いことリリースされていなかった 1.0.0 が出るということは それだけ drone が成熟してきたということの表れとも言えます (誤解なきように言っておくと、0.8.xでも既に本番運用できる品質だと思います)。 1.0.0 が出てないが故に drone を敬遠する方もいらっしゃるようですが 1.0.0 が出たらそういった方にも drone を使っていただきたいです (もっともリリース直後はまだバグもあったりする可能性があるのでしばらく様子は見たほうが無難かもしれませんが)。

この記事が皆さんの drone 1.0.0 の導入の手助け・参考になれば幸いです。

明日は freddi さんによる「SwiftのType-checkが遅くなる理由を探求してみた」です。お楽しみに!

Related Post