CircleCI の “パイプラインのスケジュール実行” 機能を利用すると、パイプラインを定期的に実行できるようになります。時間ごと、日ごと、週ごとなど、実行間隔も設定可能です。 ワークフローのスケジュール機能を使ったことがある方なら、今度はパイプラインをスケジュールできるようになったことで、パフォーマンス、管理性、柔軟性がさらに高まるとおわかりいただけるでしょう。 このチュートリアルでは、パイプラインのスケジュール実行のしくみと便利なユースケースをご紹介した後、実際に使い始めるための方法をご説明します。 API を使う方法と、UI を使う方法、ゼロから設定を行う方法、ワークフローのスケジュール機能からの移行方法まで、漏れなくお伝えします。

前提条件

このチュートリアルでは、次のものが必要です。

本記事の手順では、こちらのサンプル プロジェクトを使用します。

定期的なビルドとテストをスケジュールで実行する

さまざまな理由から、CI/CD パイプラインはリポジトリへのコードのプッシュ時にだけ実行するのではなく、スケジュールに応じて繰り返し実行することがお勧めです。 すぐに思い浮かぶ、自明と言ってもよい理由は、ソフトウェアを定期的にビルドできるからです。 開発チーム以外の人々 (プロダクト マネージャーや QA エンジニアなどの関係者) はしばしば、開発中のソフトウェアのうち最新版のビルドにアクセスする必要に迫られます。 もちろん、ビルドは必要に応じていつでも手動で開始できますが、開発チームにとっては作業の妨げになりかねません。 ビルド プロセスを自動化し、すべての関係者が最新のビルドを見つけられるようにした方が、はるかに楽です。 Web アプリやモバイル アプリ、バックエンド サービス、ライブラリ、その他のさまざまな開発要素にも同じことが言えます。

ビルドをスケジュール設定すれば、開発作業が行われていない夜間や業務時間外に、ソフトウェアを自動でビルドすることができます。 このような通称 “ナイトリー ビルド” では、メイン ブランチの最新のリビジョンを用いて、ステージング版やベータ版のビルドを作成します。

パイプラインのスケジュール実行機能では、テスト スイート全体を実行することも可能です。ナイトリー ビルドにこの機能を組み合わせることで、夜のうちに開発中のソフトウェアの動作を検証してから、次の日の作業を始めることができます。 高コストで時間のかかる機能テストや統合テストなどは、コミットのたびに実行するのは大変ですが、スケジュール機能があれば問題は解決するというわけです。 もちろん、ビルドを毎晩行わなくてもかまいません。 数時間ごと、場合によっては数十分ごとなど、チームに合ったペースでスケジュール実行しましょう。

他の作業もスケジュール実行する

ビルドだけがスケジュール実行の対象ではありません。 バッチ処理、データベースのバックアップ、サービスの再起動など、ビルド以外の定期プロセスもスケジュール実行できます。 お使いの環境へのアクセス権があるマシンのスクリプトに追加できる作業であれば、CI/CD システムの中で実行可能です。

従来のスケジュール実行機能: ワークフローのスケジュール

特定のスケジュールで実行する機能は、CircleCI にとって特段新しいものではありません。 これまでは、CircleCI 設定ファイルの中において、cron 構文によりワークフロー レベルのスケジュールを設定することができました。 ただし、このアプローチにはいくつかの弱点もありました。

  • スケジュールを変更する場合だけでなく、設定済みのスケジュールを確認する場合にも開発者が行うような作業が必要
  • CircleCI の場合、トリガーされるのはワークフローではなくパイプライン
  • トリガー対象の作業をだれがスケジュールしたのかわからない場合があり、権限の細かい調整が困難

パイプラインのスケジュール実行機能でデベロッパー エクスペリエンスはこう変わる

パイプラインのスケジュール実行には次のようなメリットがあります。

  • 渡したいパイプライン パラメーターも含め、パイプラインの実行全体をスケジュールできる。
  • 設定ファイルの外部でスケジュールを設定するので、API 経由や UI 経由でスケジュールの確認や設定を行える。 これにより、スケジュールと実行の管理がさらに柔軟になります。
  • パイプラインのスケジュール実行ではコンテキストが使用できる。 コンテキストとは、特定のジョブに関して、実行とスケジュール設定の権限をだれに付与するか、きめ細かく設定するためのしくみです。 デプロイの資格情報にアクセス可能なユーザーを、適切な権限があるエンジニアのみに制限し、他の人物によるスケジュール設定を禁止できます。 ダイナミック コンフィグ機能も組み合わせて、CI/CD の設定の柔軟性をさらに高めることもできます。

パイプラインのスケジュール実行機能に関する基本事項を把握できたところで、実際に実装してみましょう。

パイプラインのスケジュール実行を実装する

まずは、スケジュールを設定するためのパイプラインが必要です。 こんなこともあろうかと、ワークフローのスケジュールを使用するプロジェクトをご用意しました。 夜間にデプロイを行うオープンソースの Android ライブラリ プロジェクトなので、パイプラインのスケジュール実行のユースケースにぴったりです。 GitHub でこのプロジェクトをフォークし、CircleCI にプロジェクトとして設定してください。

このサンプルのスケジュールは、毎晩ビルドを実行して、Sonatype スナップショット リポジトリにデプロイするというものです。 毎日ビルドが行われるので、だれでもリポジトリから最新のコードを入手できるようになっています。

サンプルの .circleci/config.yml では、次の nightly-snapshot ワークフローを定義しています。

  parameters:
    run-schedule:
        type: boolean
        default: false

  nightly-snapshot:
    when: << pipeline.parameters.run-schedule >>
    jobs:
      - android/run-ui-tests:
          name: ビルドおよびテスト
          system-image: system-images;android-23;google_apis;x86
          test-command: ./gradlew assemble sample:connectedDebugAndroidTest
      - deploy-to-sonatype:
          name: スナップショットを Sonatype にデプロイする
          requires:
            - ビルドおよびテスト

このワークフローには 2 つのジョブがあります。1 つはテストの実行、もう 1 つはスナップショットのデプロイです。 パイプラインそのものにスケジュールの設定はありません。when 文で、run-schedule パイプライン パラメーターを確認しているだけです。 このパラメーターは、CircleCI のスケジューラーによりパイプラインのトリガー時に設定されます。

API からパイプラインのスケジュール実行機能を使用する

API を使用してパイプラインをスケジュールするには、API トークンが必要です。 トークンを取得するために、まず CircleCI にログインして左下にあるアバターをクリックします。 アバターをクリックすると、[User settings (ユーザー設定)] が開きます。 [Personal API Tokens (パーソナル API トークン)] に移動して、新規トークンを作成し、安全な場所に保存してください。 サンプル プロジェクトでは、build-scheduling ディレクトリが用意されており、そこに .env.sample というファイルがあります。 このファイルを .env という名前でコピーし、プレースホルダー トークンを先ほど取得したものに置き換えてください。 .env ファイルの PROJECT_IDORG_NAME についても、同様の編集を行います。

CIRCLECI_TOKEN=<使用する CircleCI トークン>
PROJECT_ID=<実際のプロジェクト ID>
ORG_NAME=<VCS ユーザー名>
VCS_TYPE=github

環境変数を設定できたところで、次は API 呼び出しを作成しましょう。 パイプラインのスケジュール実行機能では、CircleCI API v2 を使用します。 新規のスケジュールを送信するには、エンドポイント宛ての POST リクエストを作成する必要があります。 エンドポイントは、CircleCI プロジェクト名、ユーザー名、VCS プロバイダー名で構成されます。 たとえば、以下のようになります。

https://circleci.com/api/v2/project/github/zmarkan/android-espresso-scrollablescroll/schedule

このサンプルでは、setup_nightly_build.js スクリプト内の POST 呼び出しで Axios JavaScript ライブラリを使用しています。

const token = process.env.CIRCLECI_TOKEN

axios.post("https://circleci.com/api/v2/project/github/zmarkan/android-espresso-scrollablescroll/schedule", {
    name: "ナイトリー ビルド",
    description: "ビルドを実行し作成されたビルドを Sonatype スナップショットにプッシュするプロセスを 毎日夜間に実行",
        "attribution-actor": "system",
        parameters: {
          branch: "main",
          "run-schedule": true
        },
        timetable: {
            per_hour: 1,
            hours_of_day: [1],
            days_of_week: ["TUE", "WED", "THU", "FRI", "SAT"]
        }
    },{
        headers: { 'circle-token': token }
    }
)

本文のペイロードにスケジュール名を一意の名前で設定します。説明も任意で追加できます。 実行ユーザー (attribution-actor) には system または current を指定します。前者ではデフォルトのアクセス権を使用し、後者では (トークンに基づく) 現在のユーザーの権限を使用します。 ペイロードには、パイプラインのトリガーに使用するブランチを指定するパラメーターや、その他の設定済みパラメーターも含まれています。 このチュートリアルでは、設定ファイルで run-schedule を使用しています。 後半の timetable の部分では、パイプラインのスケジュール実行のタイミングと頻度を定義しています。 ここで使用できるフィールドは、per_hourhours_of_daydays_of_week です。 cron 式は使用できません。これは、API を使用する側である、人間にとって理解しやすい形式にしているからです。

ヘッダーでは circle-token を渡しています。これは、さきほど CircleCI の UI で生成しておいたトークンです。

timetable では、火曜日から土曜日まで、業務終了後の午前 1 時 (協定世界時) に実行するように各項目を設定してあります。 このサンプル プロジェクトでは週末に作業しないので、日曜日と月曜日には実行する必要がありません。 土日にコードベースが変更されることはないからです。

API では POST メソッド以外のメソッドも使用できます。スケジュールの取得、削除、更新は、それぞれ GET、DELETE、PUT の各メソッドで行えます。 get_schedules.jsdelete_schedule.js のサンプルがリポジトリにありますので、ぜひご覧ください。

GUI を使用する

API ではなく、CircleCI のダッシュボードからパイプラインのスケジュール実行を直接設定することもできます。 CircleCI のプロジェクトから [Project Settings (プロジェクト設定)] に移動し、左側のメニューから [Triggers (トリガー)] を選択します。

[Add Scheduled Trigger (スケジュール実行のトリガーを追加)] をクリックすると、新しいパイプラインのスケジュール実行の設定ページが開きます。 オプションは API の場合と同様で、トリガー名、曜日、開始時間、パラメーター、実行ユーザーなどを選択できます。

[Save Trigger (トリガーを保存)] をクリックしてアクティブ化します。 これでトリガーの準備が整い、指定の日時にパイプラインのスケジュール実行が開始されるようになります。

GUI を使用したトリガーのセットアップ

ワークフローのスケジュール機能から移行する

ここまでは、API と GUI を使ってパイプラインのスケジュールを設定し、確認する方法について述べてきました。 次は、既存のスケジュール済みのワークフローから、もっと便利なパイプラインのスケジュール実行に移行する方法を見てみましょう。

ワークフローのスケジュールの例を次に示します。スケジュールはすべて、設定ファイルで定義済みです。 ワークフローの定義にトリガー設定を含め、スケジュールは cron 式で渡しています。

nightly-snapshot:
    triggers: # ビルドのスケジュール実行を指定するために使用
      - schedule:
          cron: "0 0 * * *" # cron 構文でスケジュールを設定
          filters:
            branches:
              only:
                - main
    jobs:
      - android/run-ui-tests:
          name: ビルドおよびテスト
          system-image: system-images;android-23;google_apis;x86
          test-command: ./gradlew assemble sample:connectedDebugAndroidTest
      - deploy-to-sonatype:
          name: スナップショットを Sonatype にデプロイする
          requires:
            - ビルドおよびテスト

このサンプル コードは、毎日午前 0 時に、メイン ブランチでのみトリガーされ、実行されます。

移行手順は次のとおりです。

  1. スケジュールするパイプラインの中で、nightly-snapshot ワークフローをトリガーする
  2. run-schedule という新しいパイプライン変数を導入する
  3. 各ワークフローに when 文を追加する。この文により、run-scheduletrue の場合と run-schedulefalse の場合とで、実行するワークフローをそれぞれ指定します。
parameters:
  run-schedule:
    type: boolean
    default: false

workflows:
  build-test-deploy:
    when:
      not: << pipeline.parameters.run-schedule >>
    jobs:
      ...

  nightly-snapshot:
    when: << pipeline.parameters.run-schedule >>
    jobs:
      ...

残りのプロセスは、ゼロから設定する場合と同じです。

  1. cron 式を解決する。こちらのオンライン ツールなどを参考にしてください。
  2. API または GUI のタイムテーブル設定機能でスケジュールを設定し、run-schedule パイプライン パラメーターも設定する。

まとめ

パイプラインのスケジュール実行は、次の機能を備えた汎用的な CI/CD ツールです。

  • ビルドを定期的にトリガーする
  • パイプライン パラメーターを活用する
  • パイプラインの設定者ごとに細かく制御する
  • CircleCI コンテキストを使用して、パイプラインの実行時に求められる権限を明確に定義する

このチュートリアルでは、CircleCI でパイプラインのスケジュール実行が行われるしくみと、ゼロから設定する方法、スケジュール済みのワークフローから移行する方法について説明しました。 また、API と Web UI でスケジュールを設定する方法と、すぐに使えるユースケースも紹介しました。

みなさまのチームならではのパイプラインのスケジュール実行の使い方や、ワークフローのスケジュールからの移行の体験談、UI または API に関する機能追加の要望があれば、ぜひお聞かせください。

ご意見やご感想、次の記事で取り上げてほしいテーマなどがございましたら、Twitter の @zmarkan までご連絡ください。