生産性向上ブログ@miyajan

圧倒的生産性向上を目指すエンジニアのためのブログ

CircleCI 2.0 で定期実行ジョブ(Nightly Builds)を実現する

今回は、CircleCI の小ネタです。

CI を行っていると、cron 的な定期実行ジョブを実現したいときがあります。例えば、毎回実行される CI/CD に入れるには重すぎる、セキュリティチェックや性能検証などを夜間にデイリーで実行したいような場合です。今回は、CircleCI 2.0 で定期実行ジョブを実現する方法について書きます。

CircleCI 1.0

まず、これまでとの比較のために CircleCI 1.0 のときにどうやって実現していたかを書きます。CircleCI 1.0 のときは、公式ドキュメントの Nightly Builds というページに定期実行ジョブを実現する方法が書かれていました。

https://circleci.com/docs/1.0/nightly-builds/

簡単に3行でまとめると、

  1. 自前で cron (もしくは AWS Lambda とか) を用意
  2. ビルドスクリプト内で環境変数で条件分岐
  3. 自前 cron から環境変数を指定してビルドを実行するAPIを定期的に叩く

となります。

CircleCi 2.0

まず、現時点では1.については変わっておらず、これまで通り自前で cron の役割を果たすものを用意する必要があります。

2.については、2.0 では複数のジョブを定義できるようになったので、めんどくさい条件分岐を書かなくてもよくなりました。

version: 2
jobs:
  build:
    docker:
      - image: buildpack-deps:trusty
    steps:
      - run:
          command: echo 'build'
  nightly-build:
    docker:
      - image: buildpack-deps:trusty
    steps:
      - run:
          command: echo 'nightly-build'

上記のように書くと、通常コミット時は build で定義されたジョブだけが実行されます。

nightly-build で定義されたジョブを実行するためには、ジョブ名を指定して API を叩きます。この方法については、新しくドキュメントが用意されています。

https://circleci.com/docs/2.0/api-job-trigger/

今回の場合、curl で以下のように叩くと nightly-build ジョブのみが実行されます。

curl -u ${CIRCLE_API_TOKEN}: \
     -d build_parameters[CIRCLE_JOB]=nightly-build \
     https://circleci.com/api/v1.1/project/github/miyajan/circleci-2.0-nightly-build/tree/master

AWS Lambda なりで上記のコマンドを定期実行させるようにすれば、CircleCI 2.0 で定期実行ジョブが実現できます。

APIのトークン作成は、プロジェクトの設定画面の Permissions -> API Permisions から作成できます。

f:id:miya-jan:20170723165125p:plain

Scope は All を選択しないとビルドをトリガできないです。

f:id:miya-jan:20170723165137p:plain

ちなみに、CircleCI 2.0 には Workflows というパイプライン的なフローを実現する機能がありますが、残念ながら API 経由だとこの機能は使えません。

https://discuss.circleci.com/t/workflows-job-build-not-found/13549

定期実行ジョブでそこまで複雑なフローを組むことはあまりないとは思いますが、注意が必要です。

まとめ

CircleCI 2.0 で定期実行ジョブを実現する方法について説明しました。

大まかな流れは 1.0 のときと変わらないですが、ジョブを複数定義できるようになったので 2.0 の方が自然に定期実行ジョブを記述できるようになったと思います。

CircleCI 側が Travis CI の Cron Jobs のような定期実行ジョブの仕組みを作ってくれるのが一番望ましいのですが、計画としてはあるようなので、今はこれまで通り自力で API を叩く運用で回避するしかなさそうです。

Jenkins Pipeline の when + branch は通常のパイプラインジョブでは使えない

Jenkins Pipeline についての小ネタメモです。

まず、when + branch の条件について簡単に説明しますと、ビルドが特定のブランチに対して実行されるときだけ処理を実行するように書ける文法です。

pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Example Deploy') {
            when {
                branch 'production'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

↑の例をマルチブランチパイプラインジョブで実行すると、production ブランチに対してトリガされたときだけ “Example Deploy” ステージが実行されます。

しかし、これを通常のパイプラインジョブで実行すると、ブランチに production を指定しても、

Stage 'Example Deploy' skipped due to when conditional

としてスキップされてしまいます。

不具合かと思って関連issueをウォッチしていたのですが、どうやらこれは仕様となったようです。公式ドキュメントにも明記されました。

branch
Execute the stage when the branch being built matches the branch pattern given, for example: when { branch ‘master’ }. Note that this only works on a multibranch Pipeline.

内部的に通常のパイプラインジョブとマルチパイプラインジョブでソースコード管理に依存しているプラグインが異なるのが原因なのですが、ユーザー側としては通常のパイプラインジョブでも同様に使えるほうが自然に思えるので、残念です。前回の記事で書いたように、通常のパイプラインジョブでもパラメータでブランチ名を受け取ってビルドのような用途は普通にありそうです。

一応、expression で git コマンドを叩いてブランチ名を比較するという回避策が issue のコメント上で紹介されていました。

when {
  expression {
    return sh(script: "git rev-parse --abbrev-ref HEAD", returnStdout: true).trim() == "master"
  }
}

ただ、手元で試したところ、通常だとブランチ指定子を設定しても Detached HEAD 扱いになるので、SCM の追加処理で “Check out to specific local branch” を設定しないとダメでした。(関連issue

通常のパイプラインジョブでブランチ名による分岐をしたいときは要注意です。

Jenkins Pipeline でパラメータ(環境変数)でビルドするブランチを指定する

小ネタメモです。

Jenkins のジョブを作るときに、パラメータを受け取ってその値を環境変数としてブランチに指定することがあると思います。

f:id:miya-jan:20170712224729p:plainf:id:miya-jan:20170712224740p:plain

↑こんな感じですね。

しかし、この方法を Jenkins Pipeline で行うとエラーが出ます。

hudson.plugins.git.GitException: Command "git fetch --tags --progress origin +refs/heads/${BRANCH_NAME}:refs/remotes/origin/${BRANCH_NAME} --prune" returned status code 128:
stdout: 
stderr: fatal: Couldn't find remote ref refs/heads/${BRANCH_NAME}

どうやら環境変数が解決されないようなので調べてみると、SCM の設定で “Lightweight checkout” を無効にしないといけないようです。(関連issue

f:id:miya-jan:20170712224812p:plain

“Lightweight checkout” は Jenkinsfile を master で取得するときにリポジトリ全体をチェックアウトせずに Jenkinsfile だけ取得する仕組みのようです。なので、無効にすると master 側のディスク使用量などが若干増加すると予想されます。

Jenkins の Multibranch Pipeline で Jenkinsfile のパスを指定できるようになった件

Pipeline Multibranch Plugin の 2.15 で、表題の通り Jenkinsfile のパスを指定できるようになったのでメモです。

[JENKINS-34561] Allow to detect different Jenkinsfile filenames - Jenkins JIRA

f:id:miya-jan:20170607222602p:plain

これまではリポジトリ直下の Jenkinsfile で決め打ちだったのが、↑の画像のようにパスを指定できるようになっています。

この改善は、Multibranch Pipeline だけでなく、Organization Folder にも適用されています。ちなみに、通常のシンプルな Pipeline ジョブはこれまでもパスを指定できました。

この変更によって、

  • 1リポジトリで複数の Multibranch Pipeline を作成したい
  • リポジトリのルートには決まったファイル以外を置けない・置きたくない

という場合に嬉しそうです。他のCIサービスだと1リポジトリ1パイプラインで設定ファイルの名前が決め打ちであることが多いので、おもしろい取り組みです。

一方で、1つの Multibranch Pipeline につき1ファイルしかジョブとして認識できないのは以前と変わらずでした。Organization Folder では複数のパスを Project Recognizaers として指定できるのですが、その場合でも1リポジトリ1ファイルまでしか認識されません。

つまり、例えばモノレポ方式で1リポジトリにたくさんのプロジェクトがあってそれぞれに Jenkinsfile を用意する場合、複数の Multibranch Pipeline を作成するしかなく、ちょっと面倒です。

[JENKINS-35415] Multiple branch projects per repository with different recognizers - Jenkins JIRA

この件については、↑に別 issue として登録されています。CloudBees 社が提供する Jenkins Enterprise ではすでに機能としてあるようです。

UI 面での複雑さはありそうですが、個人的には Organization Folder 1つで完結してほしいので、今後に期待です。

『カエルを食べてしまえ! 新版』読了

カエルを食べてしまえ!  新版

カエルを食べてしまえ! 新版

『カエルを食べてしまえ! 新版』を読み終えたので、簡単に感想とかのまとめです。

ちょっと変わったタイトルですが、内容を一言でまとめると、最も重要で厄介なこと(=カエル)を最優先で実行しましょう、という本です。量は少なく、1〜2時間くらいあれば読めてしまうくらいでした。

もう少し掘り下げると、以下のような内容が書かれています。

  • 目標をはっきりさせる
  • きちんと計画を立てる
  • 重要な上位20%のことに集中する
  • 大きく複雑なことでも一歩ずつ進めていく
  • 自分にしかできないことを見つける
  • 時間の浪費をやめる
  • 切迫感を持つ
  • 仕事を中断しない

まっとうな内容でしたし、個人的にはできていない部分がけっこうあったので、いろいろ考え直すきっかけになる本でした。「1日のタスクは前日に計画しておくと翌日までにアイディアが浮かんで仕事が捗る」とか、「自己鍛錬とは、自分がすべきことを好きであろうとなかろうとできるようになること」とか、なるほどなと思う部分は多かったです。

一方で、科学的な検証とかはあまりない本です。実際にこれを実現した人とそうでない人で、なにが違ってくるのかといった説明はほとんどないです。また、「切迫感を持とう」とか、「やりとげるまでは他のことに気を取られないようにしよう」みたいな部分は、精神論に近いものを少し感じ、それを実現するために具体的にどうすればいいんだろうと疑問のまま終わる説明も多かったです。

筆者はビジネス寄りの人のようなので、そこまで理詰めな内容ではなく、どちらかというと精神面重視の啓発書という感想です。ただ、文章は読みやすく、「原則」という形で気をつけるべき内容もきれいにまとまっているので、気軽に読める本だと思います。誰にでもオススメというほどではないですが、なんとなく仕事に集中できていないと感じている人とかには習慣を考え直すきっかけになるかもしれません。