GitHub Actions と enebular CLI で、フローのデプロイ作業をまるごと自動化する

前回の記事では、enebular CLIを使って「ZIPファイルのクラウド実行環境へのデプロイ」をやってみました。

今回の記事では、Node-REDのフローをenebular CLIを使ってデプロイしてみます。具体的には、enebular CLI と GitHub Actions を組み合わせて、開発用 Project から本番用 Project へフローをコピーし、そのまま本番用のクラウド実行環境へデプロイする方法をご紹介します。

はじめに

開発用 Project で動作確認したフローを、本番用 Project に反映するとき、こんな経験はないでしょうか。

  • フローをエクスポートして本番にインポート、デプロイ、バージョン作成…と画面を行き来する
  • 反映するたびに手順書を見返す
  • 急ぎの修正でステップを飛ばしてしまい、後から「あの環境、デプロイし忘れていた」と気づく

こうした作業は、一度 GitHub Actions に載せてしまえば、誰がやっても同じ手順で実行できます。バージョン作成までセットで行えるので、本番反映の履歴も自然に残ります。

今回やること

今回は、enebularの開発環境で用意したフローを本番環境のクラウド実行環境でデプロイするのをGithub Actionsのワークフローで実現します。

GitHub Actions から、以下の 3 つの処理を順番に実行します。

  1. enebular copy flow で開発用 Project から本番用 Project へフローをコピー
  2. enebular deploy cloud でコピー後のフローを本番用クラウド実行環境へデプロイ
  3. enebular add flow-version で本番用 Project 側にバージョンを作成

GitHub Actions にしておけば、開発用 Project で確認済みのフローを本番用 Project に反映する手順を自動化できます。

処理の全体像は次のとおりです。

開発用 Project ──→ [ GitHub Actions ] ──→ 本番用 Project
                    1. copy flow
                    2. deploy cloud
                    3. add flow-version

事前準備

この記事の手順を試す前に、以下を準備してください。

  • enebular のアカウント
  • 開発用 Project
  • 本番用 Project
  • 開発用 Project に登録済みのフロー
  • 本番用 Project のクラウド実行環境
  • GitHub リポジトリ
  • enebular で発行したアクセスキー / シークレットキー

enebular CLI は Node.js 22 以上で利用できます。GitHub Actions 側でも Node.js 22 を利用します。

enebular CLI は npm で公開されています。ローカル環境で試す場合は、以下のコマンドでインストールできます。

npm install -g @uhuru/enebular-cli

インストール方法や CLI の詳細については、@uhuru/enebular-cli – npm をご確認ください。

開発用と本番用の Project を用意する

今回は、開発用 Project にフローを作成し、その内容を GitHub Actions から本番用 Project にコピーしてデプロイします。

まずは、開発用 Project 側にデプロイ対象となるフローを用意します。

続いて、開発用 Project 側でフロー詳細画面を開き、対象のフローを確認します。この画面は、開発用 Project 側のフローを確認する例です。

本番用 Project 側は、コピー先として使います。まだフローが存在しない状態でも問題ありません。既存のフローを更新したい場合のみ、本番用フロー ID を入力します。

GitHub Actions の workflow を作成する

それでは、GitHub Actions の workflow を作成します。今回は手動実行で試しやすいように、workflow_dispatch を使った例を紹介します。

GitHub 上で workflow を登録する場合は、まずリポジトリの Actions タブを開き、New workflow をクリックします。

Actions タブから New workflow を開く

続いて、テンプレート選択画面が表示されたら set up a workflow yourself をクリックします。

set up a workflow yourself を選択する

workflow の核となる 3 ステップ

workflow の中身を見る前に、核となるステップについて抜粋して説明します。残りの部分(入力欄の定義、Node.js のセットアップ、認証情報の検証)は、この 3 ステップを実行するための土台です。

- name: Copy flow from development to production
  run: |
    enebular copy flow \
      --from-project-id "$SOURCE_PROJECT_ID" \
      --from-asset-id "$SOURCE_FLOW_ASSET_ID" \
      --to-project-id "$DESTINATION_PROJECT_ID" \
      --with-credentials \
      --json

- name: Deploy copied flow to production cloud execution environment
  run: |
    enebular deploy cloud \
      --project-id "$DESTINATION_PROJECT_ID" \
      --cloud-id "$DESTINATION_CLOUD_ID" \
      --asset-id "$DESTINATION_FLOW_ASSET_ID" \
      --asset-type flow \
      --json

- name: Create flow version
  run: |
    enebular add flow-version \
      --project-id "$DESTINATION_PROJECT_ID" \
      --asset-id "$DESTINATION_FLOW_ASSET_ID" \
      --name "$FLOW_VERSION_NAME" \
      --comment "$FLOW_VERSION_COMMENT" \
      --json

ここで重要なポイントは 2 つあります。

1 つは、copy flow の結果として返ってくる assetId を、後続の deploy cloudadd flow-version で同じフローの ID として使い回している点です。新規にフローを作成した場合は事前に ID が分からないため、コピー結果から取り出して引き継ぐ必要があります。

もう 1 つは、すべてのコマンドに --json オプションを付けている点です。GitHub Actions では対話的な確認ができないため、これがないと workflow が確認プロンプトで止まってしまいます。

全体の workflow ファイル

.github/workflows/ 配下に任意のファイル名で workflow ファイルを作成し、以下の内容を記述します。ここでは例として deploy-enebular-flow.yml という名前を使います。

name: 📝 enebular ブログ記事用Flowのデプロイ

on:
  workflow_dispatch:
    inputs:
      source_project_id:
        description: "Development project ID"
        required: true
        type: string
      source_flow_asset_id:
        description: "Development flow ID"
        required: true
        type: string
      destination_project_id:
        description: "Production project ID"
        required: true
        type: string
      destination_flow_asset_id:
        description: "Production flow ID (optional: update existing)"
        required: false
        type: string
      destination_cloud_id:
        description: "Production cloud execution environment ID"
        required: true
        type: string
      flow_version_name:
        description: "Flow version name"
        required: true
        default: "gha_flow_v1"
        type: string
      flow_version_comment:
        description: "Flow version comment"
        required: true
        default: "Deployed from GitHub Actions"
        type: string

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    env:
      ENEBULAR_ACCESS_KEY: ${{ secrets.ENEBULAR_ACCESS_KEY }}
      ENEBULAR_SECRET_KEY: ${{ secrets.ENEBULAR_SECRET_KEY }}
      FLOW_VERSION_NAME: ${{ github.event.inputs.flow_version_name }}
      FLOW_VERSION_COMMENT: ${{ github.event.inputs.flow_version_comment }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"

      - name: Install enebular CLI
        run: npm install -g @uhuru/enebular-cli@1.0.0

      - name: Validate credentials
        run: |
          set -euo pipefail

          if [ -z "${ENEBULAR_ACCESS_KEY}" ] || [ -z "${ENEBULAR_SECRET_KEY}" ]; then
            echo "GitHub Secrets ENEBULAR_ACCESS_KEY and ENEBULAR_SECRET_KEY are required."
            exit 1
          fi

      - name: Copy flow from development to production
        id: copy_flow
        env:
          SOURCE_PROJECT_ID: ${{ github.event.inputs.source_project_id }}
          SOURCE_FLOW_ASSET_ID: ${{ github.event.inputs.source_flow_asset_id }}
          DESTINATION_PROJECT_ID: ${{ github.event.inputs.destination_project_id }}
          DESTINATION_FLOW_ASSET_ID: ${{ github.event.inputs.destination_flow_asset_id }}
        run: |
          set -euo pipefail

          cmd=(
            enebular
            copy flow
            --from-project-id "$SOURCE_PROJECT_ID"
            --from-asset-id "$SOURCE_FLOW_ASSET_ID"
            --to-project-id "$DESTINATION_PROJECT_ID"
            --with-credentials
            --json
          )

          if [ -n "$DESTINATION_FLOW_ASSET_ID" ]; then
            cmd+=(--to-asset-id "$DESTINATION_FLOW_ASSET_ID")
          fi

          "${cmd[@]}" | tee copy_flow_result.json

          asset_id="$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync('copy_flow_result.json','utf8')); if(data.result!=='success'||!data.assetId){process.exit(1)}; process.stdout.write(String(data.assetId));")"
          echo "asset_id=$asset_id" >> "$GITHUB_OUTPUT"

      - name: Deploy copied flow to production cloud execution environment
        env:
          DESTINATION_PROJECT_ID: ${{ github.event.inputs.destination_project_id }}
          DESTINATION_CLOUD_ID: ${{ github.event.inputs.destination_cloud_id }}
          DESTINATION_FLOW_ASSET_ID: ${{ steps.copy_flow.outputs.asset_id }}
        run: |
          set -euo pipefail

          enebular \
            deploy cloud \
            --project-id "$DESTINATION_PROJECT_ID" \
            --cloud-id "$DESTINATION_CLOUD_ID" \
            --asset-id "$DESTINATION_FLOW_ASSET_ID" \
            --asset-type flow \
            --json

      - name: Create flow version
        env:
          DESTINATION_PROJECT_ID: ${{ github.event.inputs.destination_project_id }}
          DESTINATION_FLOW_ASSET_ID: ${{ steps.copy_flow.outputs.asset_id }}
        run: |
          set -euo pipefail

          enebular \
            add flow-version \
            --project-id "$DESTINATION_PROJECT_ID" \
            --asset-id "$DESTINATION_FLOW_ASSET_ID" \
            --name "$FLOW_VERSION_NAME" \
            --comment "$FLOW_VERSION_COMMENT" \
            --json

エディタ画面が開いたら、任意のファイル名を入力し、上記の内容を貼り付けます。入力が終わったら、右上の Commit changes... をクリックします。

workflow ファイルを編集して Commit changes を押す

最後にコミットメッセージを入力して保存します。既存ブランチへ直接 commit してもよいですし、必要に応じて新しいブランチを作成して pull request を作る形でも問題ありません。

workflow ファイルを commit する

workflow のポイントを見る

ここからは、workflow の中で押さえておきたいポイントを順に見ていきます。

copy flow で Project 間コピーを行う

今回の起点となるのは、enebular copy flow を使って開発用 Project から本番用 Project にフローをコピーしている点です。これにより、開発用 Project で確認したフローを本番用 Project に反映しやすくなります。

また、destination_flow_asset_id を指定しない場合は本番用 Project に新規作成され、指定した場合は既存のフローを更新する形で利用できます。最初の反映時は空欄、2 回目以降は同じフローを上書き、という運用がしやすくなっています。

コピー結果の ID を後続 step で使う

copy flow は JSON 出力を使うことで、コピー先の assetId を取得できます。workflow ではこの値を GITHUB_OUTPUT に書き出し、後続のデプロイとバージョン作成で同じフローを参照しています。

これによって、新規作成されたフローでも、続く deploy cloudadd flow-version で同じ ID を指し示せるようになります。

–json を付けて非対話実行にする

GitHub Actions では対話的な確認を行えないため、CLI 実行時には --json を付けています。--json を指定すると確認なしで実行できるため、実行結果を後続処理で扱いやすくなります。

つまずきやすいポイント

実装を進める中で、最初に試したときに引っかかりやすいポイントをまとめておきます。

  • --json を付け忘れると、対話プロンプトが出て workflow が止まります。実行ログを見て「応答待ち」のような出力が続いていたら、まずここを疑ってください。
  • ENEBULAR_ACCESS_KEY / ENEBULAR_SECRET_KEY の値の前後に空白や改行が入っていると、認証エラーになります。GitHub Secrets に登録するときは、コピー元の余分な空白を取り除いてください。
  • destination_cloud_id に別 Project のクラウド実行環境 ID を指定すると、デプロイは失敗します。destination_project_id と同じ Project に属する ID であることを確認してください。
  • copy flow の結果から assetId を取り出すスクリプトは、resultsuccess でない場合に終了コード 1 で抜けるようにしています。コピーに失敗していれば、後続の step は実行されません。

workflow に必要な値を確認する

ここまでで、GitHub Actions からどのような workflow を実行するのか、また内部でどの enebular コマンドを呼び出しているのかが分かりました。

続いて、workflow の入力欄や Secrets に必要な値を、enebular の画面からどのように確認するかを見ていきます。

CLI 用アクセスキーを作成する

GitHub Actions から enebular CLI を利用するには、認証情報を GitHub Secrets に登録する必要があります。まず、enebular 側で CLI 用のアクセスキーとシークレットキーを作成します。

画面右上のユーザーメニューを開き、アカウント設定 を選択します。

ユーザーメニューからアカウント設定を開く

アカウント設定のアクセスキー / シークレットキー管理画面から、新しいアクセスキーを作成します。

CLI 用アクセスキーの作成画面

GitHub 側では、対象リポジトリの Settings を開きます。

GitHub リポジトリの Settings を開く

左メニューから Secrets and variables を開き、その中の Actions を選択します。

Secrets and variables から Actions を選ぶ

Repository secrets の画面で New repository secret をクリックし、先ほど作成したアクセスキーとシークレットキーをそれぞれ以下の名前で登録します。

  • ENEBULAR_ACCESS_KEY :アクセスキー
  • ENEBULAR_SECRET_KEY :シークレットキー
New repository secret から Secrets を追加する

プロジェクト ID とフロー ID を確認する

workflow では、source_project_idsource_flow_asset_iddestination_project_iddestination_flow_asset_id などの入力が必要です。

これらの値は、enebular の画面でフロー詳細画面を開いたときの URL から確認できます。フロー詳細画面の URL は、たとえば以下のような形になっています。

https://enebular.com/app/project/<プロジェクトID>/flow/<アセットID>

このとき、次のように読み取れます。

  • project の後ろにある値がプロジェクト ID
  • flow の後ろにある値がフロー ID

開発用 Project 側のフロー詳細画面を開けば、source_project_idsource_flow_asset_id を確認できます。また、本番用 Project 側のフロー詳細画面を開けば、既存のフローを更新したい場合の destination_project_iddestination_flow_asset_id を確認できます。

クラウド実行環境 ID を確認する

デプロイ先として使う destination_cloud_id は、本番用 Project のクラウド実行環境設定画面から確認できます。

まず、本番用 Project で対象のクラウド実行環境を開きます。

クラウド実行環境設定画面の上部

設定画面を下にスクロールすると、実行環境ID が表示されます。この値を GitHub Actions の destination_cloud_id に入力します。

クラウド実行環境 ID の確認

また、クラウド実行環境の詳細画面の URL は以下のような形になっています。

https://enebular.com/app/project/<プロジェクトID>/execution-environment/cloud/<クラウド実行環境ID>

execution-environment/cloud の後ろにある値がクラウド実行環境 ID なので、ここから確認することも可能です。

実行してみる

workflow ファイルをリポジトリに追加したら、GitHub の Actions タブから対象の workflow を選び、Run workflow を実行します。

今回の workflow は、次のように各入力値を設定して実行します。

GitHub Actions の Run workflow 画面

実行時には以下を入力します。

  • source_project_id :開発用 Project の ID
  • source_flow_asset_id :開発用フローの ID
  • destination_project_id :本番用 Project の ID
  • destination_flow_asset_id :本番用フローの ID
  • destination_cloud_id :本番用クラウド実行環境の ID
  • flow_version_name :作成するバージョン名
  • flow_version_comment :バージョンコメント

destination_flow_asset_id は任意です。本番用 Project 側に上書きしたい既存のフローがある場合はその ID を指定し、存在しない場合は空のまま実行することで新規登録できます。

workflow が正常に完了すれば、以下の処理が順番に実行されます。

  • 開発用 Project から本番用 Project へのフローコピー
  • 本番用クラウド実行環境へのデプロイ
  • 本番用 Project 側でのフローバージョン作成

各 step のログには、--json の出力として {"result":"success", ...} が表示されます。すべての step が success で終わっていれば、反映は完了しています。

デプロイ結果を確認する

今回は destination_flow_asset_id に既存フロー demo-02 の ID を指定して実行しました。

workflow の実行後に本番用 Project のフロー一覧を開くと、指定した demo-02 が更新されていることを確認できます。

コピー後のフロー一覧

さらに、本番用 Project のクラウド実行環境一覧を開くと、コピーしたフローがデプロイ済みになっていることを確認できます。

クラウド実行環境へのデプロイ結果

また、本番用フローのバージョン一覧を開くと、GitHub Actions から作成したバージョンが追加されていることも確認できます。

フローのバージョン作成結果

応用例

今回はフローのコピーとデプロイを例にしましたが、enebular CLI では他にもさまざまな操作が可能です。

ZIP ファイルを使ったコードデプロイに広げる

たとえば、フローだけでなく ZIP ファイルを使ったクラウド実行環境へのデプロイにも応用できます。

add file を使うと、ZIP デプロイに使用するソースをファイルとしてアップロードできます。そのうえで deploy cloud 実行時に --asset-type file を指定することで、アップロードした ZIP ファイルをクラウド実行環境へデプロイできます。

今回の workflow をベースに copy flowadd file に置き換える形で、Node.js / Python のコードデプロイも GitHub Actions にまとめられます。

Private Node もまとめて反映する

フロー単体ではなく、フローと一緒に使う Private Node も反映したい場合は、以下を組み合わせます。

  • copy privatenode を使って Private Node を別 Project にコピーする
  • add privatenode-version を使って Private Node のバージョンも同時に作成する

これにより、フローと Private Node がセットで本番反映される運用に近づきます。

環境設定ごとコード管理する

クラウド実行環境の設定(HTTP トリガー、スケジュール、環境変数など)も合わせて反映したい場合は、bulk-update cloud-config を使って本番用クラウド実行環境の設定を更新できます。

設定内容を JSON ファイルとしてリポジトリに含めておけば、フローとアプリケーション設定を一緒にバージョン管理できます。

また、workflow_dispatch で手順を確認したあとは、release をトリガーにして本番反映の手順を固定化することもおすすめです。

まとめ

今回は、enebular CLI を GitHub Actions から実行し、開発用 Project から本番用 Project へフローをコピーし、そのまま本番用クラウド実行環境へデプロイする方法をご紹介しました。

Project を分けて運用している場合でも、CLI と workflow を組み合わせることで、反映手順を揃えながら自動化しやすくなります。今回ご紹介したフローのコピーとデプロイに加えて、応用例で紹介したようなコードデプロイも組み合わせることで、enebular への反映作業全体を GitHub Actions にまとめやすくなります。

まずは手動実行で反映手順を確認し、そのうえで自分たちの運用に合わせて、コードデプロイを含めた自動化へ広げてみてください。