前回の記事では、enebular CLIを使って「ZIPファイルのクラウド実行環境へのデプロイ」をやってみました。
今回の記事では、Node-REDのフローをenebular CLIを使ってデプロイしてみます。具体的には、enebular CLI と GitHub Actions を組み合わせて、開発用 Project から本番用 Project へフローをコピーし、そのまま本番用のクラウド実行環境へデプロイする方法をご紹介します。
はじめに
開発用 Project で動作確認したフローを、本番用 Project に反映するとき、こんな経験はないでしょうか。
- フローをエクスポートして本番にインポート、デプロイ、バージョン作成…と画面を行き来する
- 反映するたびに手順書を見返す
- 急ぎの修正でステップを飛ばしてしまい、後から「あの環境、デプロイし忘れていた」と気づく
こうした作業は、一度 GitHub Actions に載せてしまえば、誰がやっても同じ手順で実行できます。バージョン作成までセットで行えるので、本番反映の履歴も自然に残ります。
今回やること
今回は、enebularの開発環境で用意したフローを本番環境のクラウド実行環境でデプロイするのをGithub Actionsのワークフローで実現します。

GitHub Actions から、以下の 3 つの処理を順番に実行します。
enebular copy flowで開発用 Project から本番用 Project へフローをコピーenebular deploy cloudでコピー後のフローを本番用クラウド実行環境へデプロイ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 をクリックします。

続いて、テンプレート選択画面が表示されたら 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 cloud と add 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... をクリックします。

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

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 cloud と add 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を取り出すスクリプトは、resultがsuccessでない場合に終了コード 1 で抜けるようにしています。コピーに失敗していれば、後続の step は実行されません。
workflow に必要な値を確認する
ここまでで、GitHub Actions からどのような workflow を実行するのか、また内部でどの enebular コマンドを呼び出しているのかが分かりました。
続いて、workflow の入力欄や Secrets に必要な値を、enebular の画面からどのように確認するかを見ていきます。
CLI 用アクセスキーを作成する
GitHub Actions から enebular CLI を利用するには、認証情報を GitHub Secrets に登録する必要があります。まず、enebular 側で CLI 用のアクセスキーとシークレットキーを作成します。
画面右上のユーザーメニューを開き、アカウント設定 を選択します。

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

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

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

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

プロジェクト ID とフロー ID を確認する
workflow では、source_project_id、source_flow_asset_id、destination_project_id、destination_flow_asset_id などの入力が必要です。
これらの値は、enebular の画面でフロー詳細画面を開いたときの URL から確認できます。フロー詳細画面の URL は、たとえば以下のような形になっています。
https://enebular.com/app/project/<プロジェクトID>/flow/<アセットID>
このとき、次のように読み取れます。
projectの後ろにある値がプロジェクト IDflowの後ろにある値がフロー ID
開発用 Project 側のフロー詳細画面を開けば、source_project_id と source_flow_asset_id を確認できます。また、本番用 Project 側のフロー詳細画面を開けば、既存のフローを更新したい場合の destination_project_id と destination_flow_asset_id を確認できます。
クラウド実行環境 ID を確認する
デプロイ先として使う destination_cloud_id は、本番用 Project のクラウド実行環境設定画面から確認できます。
まず、本番用 Project で対象のクラウド実行環境を開きます。

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

また、クラウド実行環境の詳細画面の URL は以下のような形になっています。
https://enebular.com/app/project/<プロジェクトID>/execution-environment/cloud/<クラウド実行環境ID>
execution-environment/cloud の後ろにある値がクラウド実行環境 ID なので、ここから確認することも可能です。
実行してみる
workflow ファイルをリポジトリに追加したら、GitHub の Actions タブから対象の workflow を選び、Run workflow を実行します。
今回の workflow は、次のように各入力値を設定して実行します。

実行時には以下を入力します。
source_project_id:開発用 Project の IDsource_flow_asset_id:開発用フローの IDdestination_project_id:本番用 Project の IDdestination_flow_asset_id:本番用フローの IDdestination_cloud_id:本番用クラウド実行環境の IDflow_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 flow を add 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 にまとめやすくなります。
まずは手動実行で反映手順を確認し、そのうえで自分たちの運用に合わせて、コードデプロイを含めた自動化へ広げてみてください。



