2022年3月24日木曜日

GitHub Actions だけで Jenkinsfile の lint をする

 皆さん、 Jenkins 使ってますか?
私は仕事で使ってます。最近は GitHub Actions が使えるようになったので、脱 Jenkins を進めているのですが、まだまだ Jenkins とのお付き合いは続きそうな感じです。

ところで近年の Jenkins に久しぶりに触れているのですが、昔と大分変わってきた印象があります。
そのなかでも私は as Code に注力をしていっています。
Jenkinsfile を使ったジョブの定義は当然のことですが、JCasC (Jenkins Configuration as Code) を使った Jenkins そのものの as Code をしています。あとは JobDSL も使ってます。(もう GUI でぽちぽちしてジョブ作るのがしんどいなと思うようになってしまった)JCasC も JobDSL も便利なんでぜひ使ってほしいところですが、今回は Jenkinsfile の話です。

パイプラインの Validate

as Code をすると PR 出してレビューしてもらって、履歴も管理しやすいしとっても便利です。
さて、PR を出したとき Jenkinsfile の動作確認はどのようにしていますか?
もちろん「PR ブランチを指定してジョブを実行する」これでもいいです。
しかし、カッコの閉じ忘れだったり、しょうもない typo で時間を無駄にしてしまうことはないでしょうか?

そういうときは jflint が便利です。
Jenkins 2.0 (5): Jenkinsfileをコマンドラインからlintする - 生産性向上ブログ
Jenkins にはパイプラインの Validate してくれる API が備わっていますが、jflint はその呼出を簡単にできるようにしてくれたものです。(できれば公式の jenkins-cli.jar が対応してほしい)
jflint 自体は Jenkins の API を実行しているだけなので、Jenkins のインスタンスが必要になります。
通常は使っている Jenkins のインスタンスを挿せば問題ないです。
というか、そうでないと利用しているプラグインがインストールされていなくて Validate が失敗したりしてしまいます。

さて、ここで表題に戻ります。
GitHub Actions だけで Jenkinsfile の lint をする」
jflint を使った方法は Jenkins のインスタンスが必要ですが、ここでは利用している Jenkins には到達できない、もしくは汎用的・テンプレート的なリポジトリで対になる Jenkins インスタンスが存在しないと過程して GitHub Actions のみで lint します。
(※Jenkins インスタンスがあって到達可能ならそれ使ったほうがいいです)

GitHub Actions に Jenkins を起動する

GtiHub Actions ではサービスコンテナの機能があります。
テストするために DB など他のサービスがほしい場合に便利な機能です。

これを利用して Jenkins を起動し、サービスコンテナの Jenkins に Validate してもらいます。(Jenkins は使いますが GitHub Actions だけで完結します。Jenkins 使わずに Validate するのは相当しんどい。プラグインがあるしカバーしきれない…)

サービスコンテナは↓な感じで起動できます。
セットアップウィザードを無効にしないと入力待ちで止まってしまうので、このオプションは必須です。
起動したコンテナのIDは「job.services.サービス名.id」で取れるのでこれを使って steps などで操作することもできます。

    services:
      jenkins:
        image: jenkins/jenkins:lts-jdk11
        credentials:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
        env:
          # セットアップウィザードを無効
          # disable setup wizard
          JAVA_OPTS: -Djenkins.install.runSetupWizard=false
        ports:
          - 8080:8080
          - 50000:50000
  

上記例では起動したコンテナに localhost:8080 でアクセスできるので、この URL で jflint を実行すると Jenkinsfile の lint が GitHub Actions だけでできるようになります。(※これだけじゃならない)

プラグインをインストールする

さて、ここで1つ問題が発生します。起動した Jenkins はプラグインが空っぽで Validate すらできない状態になってしまっています。

デフォルトプラグイン、推奨プラグインをインストールする必要があります。
さらに、Validate する Jenkinsfile によっては追加でプラグインのインストールが必要です。
プラグインのインストールは jenkins-cli.jar の install-plugin で可能なので、これをサービスコンテナの Jenkins に対して実行すればインストールできます。

java -jar jenkins-cli.jar install-plugin -s http://localhost:8080 ws-cleanup

こんな感じですね。サービスコンテナから jenkins-cli.jar をダウンロードして実行するか、コンテナに対して exec すればできると思います。

setup-service-jenkins アクション

さて、GitHub Actions で Jenkins を起動して jflint することができそうなことはわかりました。しかし、プラグインのインストールが必要でちょっとめんどくさいです。
なので、アクションにしてみました。

https://github.com/srz-zumix/setup-service-jenkins

サービスコンテナの記述はそれぞれ必要になりますが、コンテナ ID を指定してこのアクションを実行すると必要なプラグインを Jenkins にインストールするのと、 jenkins-cli のラッパースクリプトを agent にインストールします。

      - uses: srz-zumix/setup-service-jenkins@main
        with:
          id: "${{ job.services.jenkins.id }}" # サービスコンテナの ID (job.services.サービス名.id)
          port: 8080 # ポート番号(サービスコンテナのポート設定と合わせる)
          install_suggested_plugins: true # Suggested Plugins をインストールするかどうか
          plugins_file: JenkinsPlugins.txt # 追加でインストールしたいプラグインのリストファイル
  
公式イメージからのセットアップ

例えば公式のイメージを起動した場合はプラグインが空っぽなので、install_suggested_plugins オプションを true にしてデフォルト推奨プラグインをインストールするか、プラグインが列挙されたファイルを plugins_file に指定してインストールしてください。
デフォルト推奨プラグインはこちらのファイルに列挙したものになっています。
(Suggested Plugins をインストールした状態から cli でダンプ、加工したもの)
https://github.com/srz-zumix/setup-service-jenkins/blob/main/resources/DefaultJenkinsPlugins.txt

公式イメージを使う場合はセットアップウィザードを無効にすることを忘れないでください。
現状アクション側で対応してないので、冒頭に書いたようにサービスコンテナを起動するときのオプションが必須です。

カスタムイメージからのセットアップ

例えば、実際に使用している Jenkins のベースイメージがあり、プラグインなどセットアップ済みであれば特にプラグインのインストールは不要になると思います。
おそらく公式イメージよりも都合がよいと思うのでこちらのほうがおすすめですが、クリーンな状態からテストしたい場合などは公式イメージを使うほうがおすすめです。
適宜選択してください。

jenkins-cli.jar のラッパースクリプト

このアクションを使用すると agent マシンにラッパースクリプトの jenkins-cli をインストールします。こちらはサービスコンテナの Jenkins を挿すようにしただけのラッパーです。
CLI でそこそこ自由に Jenkins を操作できるのでワークフローを作る際に使ってみてください。

GitHub Actions だけで Jenkinsfile の lint をする

最終的にできあがったワークフローはこちらです。
https://github.com/srz-zumix/github-actions-sample/blob/main/.github/workflows/reviewdog-jflint.yml

公式イメージ + suggested plugins だと ansiColor プラグインがインストールされないので、jflint で指摘されているのがわかりますね。

今後の展望

サービスコンテナで Jenkins が起動し、プラグインインストールや CLI での操作が可能になりました。今後は JCasC をロードさせて Jenkins の設定を読み込ませた状態でジョブやスクリプトを実行してみたいです。
また、Shared Library のテストが書け、実行できると思っているのでそのへんも手を付けたいです。

以上。


2022年3月10日木曜日

Include-What-You-Use の docker image を更新しました

https://hub.docker.com/repository/docker/srzzumix/iwyu/general

表題どおりです。
今まで自分が使うようにイメージを置いといただけでしたが、各 clang バージョン x Ubuntu バージョン x Multi Arch(amd64/arm64) でビルドしておいておきました。
Include What You Use は C/C++ の include の最適化をしてくれるツールです。
過去に記事を書いてますのでそのへんを参考にしてください。
ブログズミ: [C++] Include-What-You-Use で依存関係を確認する


ビルドは GitHub Actions で行っています。
https://github.com/srz-zumix/docker-iwyu 

今後は複数 arch 対応の需要が上がっていく気がしてるので今回から対応してみました。
複数 arch 対応の image をローカルでビルドする場合は、レジストリに push しながらなら OK らしく(ようは実行環境の arch しかローカルビルドできないって感じかな?)勉強になりました。
今まではビルドしたあとにタグつけて push してたのですが、これだと実行環境の arch しか push できなかったため、一度ビルドしたイメージからバージョン情報とかを取り出し、タグを生成してから再度 docker/build-push-action を実行してます。

これらのイメージは定期的にビルドするものでもないので手動トリガーでビルドするようになってます。
一部の組み合わせではビルド失敗したり、clang のインストールできなくて image のビルドに失敗してます。
需要があればちゃんと見てみますので、もしあれば issue に書いてください。

以上。