Drone + Gitea と GitLab を比較してみた

この記事は [GitLab Advent Calendar 2018](https://qiita.com/advent-calendar/2018/gitlab) の24日の記事です。

# TL;DR

何かGitLabより気軽に使えてイケてるオープンソースのSCM/CIツール無い？ってことになったので、GiteaとDrone(いつの間にかDrone.ioとは呼ばなくなった？)を試してGitlabと比較してみたメモ。

ざっくり言うと、GitLabに比べると機能は少なめだしハマりどころもそこそこあるけど、必要とする機能が満たされているならば軽快に動くことと相まって最高な環境となるもしれないと思いました。

# [Gitea](https://Gitea.io/en-us/)

go言語で書かれている非常に軽量の SCM サーバ。gogsというOSSから更なる高機能化を目的としてフォークして開発が行われており、今回は現時点の最新版の1.6を試してみました。

Giteaは1バイナリで動作して使用メモリも少なく、多くのアーキテクチャやOSで動作することが出来るため、 [Raspberry Pi でベンチマークを取った記事](https://qiita.com/kounoike/items/7c42db90c42e280e1cab)もあるぐらいです。インストールは docker はもちろん、バイナリをlinuxやwindowsで動作させることが可能です。

UI 的にはパッと見はかなりGitHubに似ていて、GitHub使いには迷うことなく使えると思います(gitbucketの件を知っている人は心配になるくらいは似ている)。オンライン編集やPullRequestはもちろん、リリース、Wiki、Issue、マイルストーン、タイムトラッカー、ヒートマップなど機能も豊富で、現在も積極的に開発が進んでいるようです（より機能が少なくシンプルな物がよければ、フォーク元のgogsがよいと思われる）。また、かなりしっかりとした日本語化が行われており、英語が苦手な人でも殆ど支障ないが、フォントが中華フォントっぽいのが気になると言えば気になるかもしれません。

<img width="864" alt="g-repo.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/5103732d-1fa5-d465-255c-aa4e99bd5984.png">


[BlackDuck Open Hub](https://www.openhub.net/)による[プロジェクトのアクティビティ](https://www.openhub.net/p/Gitea)はこんな感じで活発に開発されています。Gitea公式による他の[git系SCMとの比較](https://docs.Gitea.io/en-us/comparison/)もあるので利用する際には確認してみるのがいいと思います（逆に表を見てGitLab の機能の充実度はすごいな、と思ったりもするw）。GitLab側のGiteaとの[比較ページ](https://about.gitlab.com/devops-tools/Gitea-vs-gitlab.html)もあるのですが、git v2 の件だけが書かれていました。

<img width="903" alt="Gitea-bdch2.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/8029177e-767d-c75c-c455-543829e36267.png">

# [Drone](https://Drone.io/)

初めに書いておきますが、現時点でDroneを導入する際には注意が必要です。

現在1.0のReleaseCandidate版がリリース中のためドキュメントなどが移行期にあり記述が不足していたり、書き間違いの箇所があったりするようです。従来の0.8系のドキュメントも別途提供されているので1.0系にまだ記載のないAPIドキュメントなどはそちらを参照すると良いと思いますが、1.0で仕様変更されている箇所もあるので注意してください。なお、私自身は0.8系を使ったことは無いので、0.8系との比較記事や1.0での新機能や導入方法については既に公開されている[LINEのsuzukiさん](https://engineering.linecorp.com/ja/blog/go-oss-ci-tool-Drone-replaces-jenkins/)や、[IIJの濵﨑さん](https://eng-blog.iij.ad.jp/archives/2240)、[リクルートのakechiさん](https://qiita.com/akechi/items/332c84fc8b3eb3fabeb1)が詳しい記事を書いているのでそちらを参照してください。

DroneはGitea同様にGo言語で記述された軽量なCIシステムで、GitLabやCircleCIなどの最近のCIシステムと同様にgitリポジトリに置かれたyamlによってCIの制御を定義します。Drone自体はSCMの機能を持っていませんので、GiteaのようなSCMと連携して利用することが前提となっており、GitHubやGitLabを始め、幾つかの連携設定が公式で提供されています。連携がなされている場合にはログイン時のユーザ認証はSCM側の情報で行われるため、SCM側にユーザが登録されていればDroneで特にユーザを作成すること無くDroneにもログインができるようです。このような仕様のためDrone上のUIは必要最小限の非常にシンプルな構成になっています。1.0系になってさらにこのUIはより洗練されてさらに美しくなった印象を受けます。元から設定が簡素であることから、後で記述するようなREST APIによる完全自動セットアップもそれほど大変ではありません。

<img width="731" alt="d-buildlist.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/d1a84157-efeb-91c9-421d-ca0f773e1fa8.png">
<img width="726" alt="d-buildlog.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/45bd33e6-0930-3287-a3bb-8a5023ff6ff9.png">



動作については全てコンテナ内で実行が行われる所に特徴があり、GitLabと同様にdocker in docker やsocker bindingによるdockerの操作やserviceによるサポートコンテナの実行を行うことができます。また、GitLab同様1つのサーバと複数のクライアント(Agent/runner)を配置して並列でビルドを行うことが可能です。(1.0ではエージェントを一つだけサーバと同じ場所に配置する場合、エージェントの個別の立ち上げは不要になったようです。サーバが docker のsocketを必要とするのは、おそらくこの理由からでしょう)

一方でGitLabには無い機能としてPluginがあります。これは環境変数を経由した簡単なI/Fの仕様を実装したコンテナを用意することで、簡単な記述でそのコンテナをパイプライン中で使用することが可能となる機能です。この機能は無くてもそれほど困らないのですが、ymlの記述が簡素でわかりやすくなるので、使えるのであれば使った方がわかりやすくはなります。その他にもエクステンションやシークレットなど、GItLabと同様の機能も存在します。

余談ですが、Droneのビルドログにおけるsecretの扱いはかなりきっちりチェックされていて、単純なechoはもちろん一部分のだけの表示でも「***」と表示されて隠されてしまいます。通常は非常に頼もしいのですが、場合によっては困る場合もありそうです。確認した限りでは、末尾からn文字表示といった方法の場合にのみ表示されていました。

[doroneプロジェクトのアクティビティ](https://www.openhub.net/p/Drone-ci)はあまり活発に見えませんが、これは、1.0版のソースコードが一旦プライベートなリポジトリで開発されていて、ここには反映されていないことによることのようです。なお、当初は0.8系での検証を予定していたのですが、yamlの場所を好きに変更できる機能が1.0に入ったため、1.0に変更する事にしました。
<img width="906" alt="Drone-bdoh3.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/45cc0fa6-f9d4-c506-b201-5ff92f453c89.png">

# docker-compose.yml のサンプル

今回は、docker-compose による Gitea + Drone の同時セットアップを行いました。基本的には Drone の公式ドキュメントにあるとおりに進めればよいのですが、幾つかハマりどころもあったので、共有したいと思います。

今回用いたdocker-compose.ymlはGitea 1.6 + Drone 1.0-rc3(シングルエージェント)という構成で作成しました。少し余計な定義が入っていますが、そこは適宜修正してください。


```yaml
version: '2'

networks:
  ci:
    external: false

services:
  Drone-server:
    image: Drone/Drone:1.0.0-rc.3
    ports:
      - 3080:80
    volumes:
      - ./Drone-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always
    networks:
      - ci
    environment:
      - DRONE_GIT_ALWAYS_AUTH=false
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_SERVER_HOST=192.168.56.1:3080
      - DRONE_SERVER_PROTO=http
      - DRONE_TLS_AUTOCERT=false
      - DRONE_GITEA_SERVER=http://192.168.56.1:3000
      
  scm:
    container_name: Gitea
    image: Gitea/Gitea:latest
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - SSH_PORT=22
      - HTTP_PORT=3333
      - ROOT_URL=http://192.168.56.1:3000/
    restart: always
    networks:
      - ci
    volumes:
      - ./Gitea-data:/data
    ports:
      - "3000:3333"
      - "222:22"

```

# 自動セットアップ時のハマりどころ

今回は、docker-compose upによる初回起動後にUIの操作無く既存のリポジトリ（Giteaとのミラーリングを行うことが出来ないSCM）と同期を行ってビルド待機状態まで全自動で設定を行うっというちょっと特別な目的があり、これを実現する際に（現時点のバージョンのみかもしれませんが）ハマりどころがいくつかあったので共有します。

### Giteaの初期化自動化

Gitea の幾つかのパラメータはコンテナ起動時に環境変数経由で初期設定可能なのですが、全体から見るとはごく一部のみのためこの方法だと完全に自動化することはできませんでした。Giteaはgit自体以外の情報をDatabaseに保存していますが、実は初回起動直後はまだDatabaseは作成されていません。この状態で設定のためにREST APIを叩いてもDatabaseが無いと言うエラーが出てAPIが失敗してしまうのです。ではDatabaseがいつ作られるのかと言うと、起動後の初回アクセス時に表示されるセットアップUIの確定後に行われます。つまり、なんとかしてその初回Database設定時にお好みの設定を自動で潜り込ませる必要がありました。また、さらにREST APIでは設定できないも存在することに気づきました。

どうにか設定できないかと調査しているうち、上記の初回セットアップ時にDatabase以外にセットアップ情報が保存されるiniファイルを利用することで、環境変数やREST API経由では設定できない項目も設定できるようになることが判明しました。このiniファイルは`/data/gitea/conf/app.ini`に生成されるので、ひとまず素の設定で立ち上げたあとUI経由で設定を済ませてiniファイルを生成させた後に吸い上げ、次に一旦コンテナを破棄して再生成する際にそのファイルを配置(マウント)してコンテナを起動すると、そのiniの内容に従ってDatabaseを初期化してくれ、すぐにREST APIを受け付けるようになりました。

GiteaのREST APIのドキュメントは公開されていますが、[公式](https://try.gitea.io/api/swagger)のサイトや、自分で立ち上げたGitea上でもSwaggerが動作するため、`立ち上げたGiteaのアドレス/api/swagger`にブラウザでアクセスすると、すぐにREST APIを試してみることができて何気に便利です。

なお、バックエンドのデータベースとしていくつか選べますが、今回はデフォルトのsqliteを選択しました。しかし手元の幾つかの環境でpush 時に問題が発生してどうにもならない現象が発生しました。issueを漁ったところ、[既知の問題](https://github.com/go-Gitea/Gitea/issues/2040)ぽかったのですが、反映が次の ver 1.7になりそうだっため、ひとまずMySQLに乗り換えて回避しています。ver 1.7 がリリースされたらsqliteに戻して再確認してみようと思っています。

### Drone の初期化自動化

DroneによるCIを行うためには対象のリポジトリをあらかじめアクティベートする必要があります。SCMとの連携が設定出来ていればリポジトリの情報は自動取得されているので、あとは対象のリポジトリをREST APIでアクティベートすればyamlを読み込んでCIが自動的に走るようになります。

また、セットアップで一番嵌まったのが、Giteaからのhookを受信しないという問題でした。この直接的な原因はポート番号の未指定という単純なものでしたが、使い慣れていないこともありなかなか気づくことができませんでした。フックが正常にかかっているかどうかは、Giteaの設定→Webhookから確認することができます。GiteaがDroneと同期してactivateすることができると、ここにURLが表示されますが、送信テストは失敗して画像のように赤い×マークがつきます。正しく送信テストが行われるとこのマークが緑のチェックマーク（添付参照）になるので、このように表示されるまで修正してください。

<img width="753" alt="hook-error.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/3f9f92ad-254e-f3c6-321a-c2ad0ddeb7e5.png">
<img width="748" alt="hook-or.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96881/c71edf91-d064-f416-35a2-e792b7f5a0a1.png">


# Drone まわりのあれこれ

先にも書いたように、Droneは12/24現在1.0の正式版はまだリリースされておらず、ドキュメントも中途半端な状態なのですが、特に気になった点を上げておきます。最新の状況は[Gitter](https://gitter.im/Drone/Drone)で議論がされているので、覗いてみることをおすすめします。

### REST API

1.0向けのREST API のドキュメントは実はまだ出ていません。多くのAPIは0.8と同じ仕様なのですが、幾つか互換性が無い変更が存在します。その多くは「フィールド名の変更」だそうなのですが、そもそもその変更した後のフィード名がわからないのです。リンク先を失念してしまったのですが、開発者のBrad Rydzewski曰く、「呼び出したいAPIに対応するUI操作を行った際に呼び出しているREST APIを参考にすればいいよ」ということなので、インスペクターなどで呼び方を見ればわかると思います。

### ソースコード

私も最初は気づかずにいたのですが、実は現時点ではソースコードは公開されておらず、バイナリだけのリリースとなっています、Drone のGitHubプロジェクトはありますが、そこにあるコードは0.8系までのコードです。Brad Rydzewskiは2019年1月中には公開したいと以下のリンク先でも書いていたので、その言葉の通りであれば、来月中には0.8までと同様の方法で公開されることになると思います。

### ライセンス

この点が情報が少なくてわかりにくいのですが、おおよそは[discourceでのBrad Rydzewskiの書き込み](https://discourse.Drone.io/t/Drone-coming-with-limits-and-license/2652/23)で解決するでしょう。このコメントをざっくり意訳しておきます。

* ソースコードは2019年1月にはGitHubで公開予定で、これはCommunity EditionとしてApache 2ライセンスでリリースされ、[Enterprise Editionの機能](https://Drone.io/enterprise/)を含まない代わりにこのソースコードからビルドしてCommunityEditionを無料で利用できます
* 公式の Drone のdockerイメージはEnterprise Edition であり、5ユーザ/5リポジトリの制限が課されています
* この制限を撤廃するためにはライセンスの購入が必要ですが、[このLICENSEにあるAdditionalUseGrant](https://github.com/Drone/Drone/blob/master/LICENSE)(次行に原文のまま抜粋)を満たす企業であればEnterpriseEdition を無料で使うことが出来ます
  *  (a) annual gross revenue under (USD) $1 million (according to GAAP, or the equivalent in its country of domicile);
  *  and (b) less than (USD) $5 million in aggregate debt and equity funding.
* 上記のリンク先のライセンス情報は1.0でも0.8と同様のものが適用されます
* 十分な数の企業がEnterpriseEditionを購入してくれたならば、将来、このEnterpriseEditionで使うことが出来るユーザ数/リポジトリ数の制限をあげることが出来るでしょう
* Enterprise Editionを購入した場合には、そのソースコードを入手してビルドして利用することが可能となります
* 以前に提示されていた$50/月のプランは削除されました。これは、一ヶ月のみので契約解除する顧客が多かったことと、そもそもこの価格では収益が上がらないことが理由ですが、それでもCircleCIなどの競合他社のセルフホスティングバージョンよりは安価な価格設定です

# 最後に

Gitea+Droneの環境はGitLabに比べて機能が少なく、立ち上げ時の設定などもやや面倒な点があります。特に、ContainerRegistryやWebIDEなど、幾つかのGitLabしかない機能をお手軽に使う場合にはやはりGitLabを選択することになると思います。一方で、Gitea+Droneは非常に軽快に動作し要求されるリソースも少ないため、そこを気にされる方や、機能がGitea+Droneで十分でありSCMとCIのUIが分かれていても支障ない方には、有力な候補となると思います。Droneがちょうど1.0RCを迎えた状況であり微妙な時期ではありますが、設定が決まれば非常に安定して動作するために移行の余地は十分にあるといえるでしょう。

アドベントカレンダーに向けて急いで触ったのですが時間が足りないこともあってまだまだ機能を試し切れていません。今後ももう少し触って確認していく予定なので、余裕があれば続きを投稿したいと思います。

...思ったよりGitLabの話が少なくてごめんなさい...