💇

Cloud RUNのサービス構成をプログラムから変更する

2024/05/01に公開

やりたいこと

Cloud RUNの「環境変数」や「最小・最大インスタンス数」をNodeJSで変更したい。
これにより、スケジュールや特定のアラートで柔軟に構成を変更できる。

進め方

公式のパッケージ
https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-run

このパッケージを使って、Cloud RUNに新しい構成を送信します。
手順としては以下になります。

  1. 対象のCloud RUNから、現在の"構成"を取得する
  2. 取得した"構成"を書き換える
  3. 対象のCloudRUNに書き換えた"構成"で更新を実行する

パッケージの取得と初期化

ターミナルでパッケージを取得します
// NPMパッケージの取得
npm install @google-cloud/run
プログラムで読み込みと初期化を行います

const {ServicesClient} = require('@google-cloud/run').v2;

const runClient = new ServicesClient();

実行権限は、(ほとんどのCompute EngineやCloud RUNで使っている) 「Compute Engine default service account」で十分です。

記事の下の方に、サンプルコードを載せています。結論を見たい人は読み飛ばしてください。

現在の"構成"を取得する

現在の"構成"の取得を行います。
取得したい、Cloud RUNの名前が必要です。

下のプログラム内の定数を入れてください

  • PROJECT_ID = 「プロジェクトID」名

対象のCloud RUNの

  • LOCATION = リージョン名(この例だと"us-central1")
  • SERVICE_NAME = サービス名(この例だと"cloudrun-update-test")

対象

const {ServicesClient} = require('@google-cloud/run').v2;
const runClient = new ServicesClient();


// 定数
const PROJECT_ID = '';// 「プロジェクトID」
const LOCATION = '';// CloudRUNのリージョン名
const SERVICE_NAME= '';// CloudRUNのサービス名


const request = {
  name: `projects/${PROJECT_ID}/locations/${LOCATION}/services/${SERVICE_NAME}`
};

// Run request
const response = await runClient.getService(request);

// 構成を取得
console.log(response);

"構成"を変更して適用する

構成の中身を確認

取得した構成を確認しましょう。

上のプログラムの「response」変数の中は以下のような感じです(見やすいように減らしています)

[
  {
    labels: {},
    annotations: {},
    name: 'projects/project-hoge/locations/us-central1/services/cloudrun-update-test',
    description: '',
    createTime: { seconds: '1714544960', nanos: 97834000 },
    updateTime: { seconds: '1714544960', nanos: 97834000 },
    template: {// ここが
      containers: [Array],//コンテナごとの設定(ここに環境変数もある)
      volumes: [],
      labels: {},
      annotations: {},
      revision: '',
      scaling: [Object],// リビジョンレベルの最大・最小インスタンス数
      maxInstanceRequestConcurrency: 80,
      sessionAffinity: false,
      healthCheckDisabled: false
    },
    scaling: { minInstanceCount: 0 }// サービスレベル最小インスタンス数
  }
]

環境変数を変更したい場合

環境変数は、「template.containers」の中に(マルチコンテナなのでArray)で格納されています。

コンテナが1つなら、配列=0で取ればよいので
template.containers[0].env に格納されています。

// response変数から、環境変数へのパス
console.log(response[0].template.containers[0].env)

// この形式で格納
// [ { name: 'ここにキーが入る', value: 'ここに値が入る', values: 'value' } ]

リビジョンレベルの最大・最小インスタンス数

リビジョンレベルの最大・最小インスタンス数は template.scaling に格納されています。

// response変数から、環境変数へのパス
console.log(response[0].template.scaling);

// この形式で格納
// { minInstanceCount: 0, maxInstanceCount: 100 }

CloudRUNに書き換えた"構成"で更新

const {ServicesClient} = require('@google-cloud/run').v2;
const runClient = new ServicesClient();

const PROJECT_ID = '';// 「プロジェクトID」
const LOCATION = '';// CloudRUNのリージョン名
const SERVICE_NAME= '';// CloudRUNのサービス名

const service_template;// ここに書き換え済みの"template"

const request = {
      service: {
        name: `projects/${PROJECT_ID}/locations/${LOCATION}/services/${SERVICE_NAME}`
        "template": service_template
    },

    allowMissing : false,// サービス名が存在しない場合サービスを作成するか(false=作成しない)
};


// Run request
const [operation] = await runClient.updateService(request);
await operation.promise();

サンプルコード

サンプルコードは、以下を行います。

  • 環境変数を "key1: value1", "env: dev"に書き換える
  • リビジョンレベルの最小インスタンス数を "1"

定数のPROJECT_ID(プロジェクトID)、 LOCATION(CloudRUNのリージョン名)、SERVICE_NAME(サービス名)は自身の環境を入れてください。

package.json
{
  "dependencies": {
    "@google-cloud/run": "^1.2.0"
  },
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  }
}
index.js
const {ServicesClient} = require('@google-cloud/run').v2;

const runClient = new ServicesClient();

const PROJECT_ID = '';// 「プロジェクトID」
const LOCATION = 'us-central1';// CloudRUNのリージョン名
const SERVICE_NAME= 'cloudrun-update-test';// CloudRUNのサービス名


/**
 * 指定したサービスの構成を取得する
 */
const callGetService = async(name) => {

    const request = { name };

    // Run request
    const response = await runClient.getService(request);

    return response[0];
}


/**
 * 指定したサービスの構成を更新する
 */
const callUpdateService = async(name, service_template) => {

    const request = {
      service: {
        "name": name,
        "template": service_template
      },//サービスの更新

      allowMissing : false,// サービス名が存在しない場合サービスを作成するか(false=作成しない)
    };


    // Run request
    const [operation] = await runClient.updateService(request);
    const [response] = await operation.promise();
    
    return response;
}


const main = async() => {


    const service_name = `projects/${PROJECT_ID}/locations/${LOCATION}/services/${SERVICE_NAME}`

    console.log('Cloud RUNの構成変更の実行開始');
    console.log(`変更対象::${service_name}`)

    // 構成を取得
    const service_configuration = await callGetService(service_name);
    console.log('Cloud RUNの構成変更前');
    console.log(service_configuration);


    ////
    // 構成の変更
    let service_template = service_configuration.template;
    delete service_template.revision;// 構成が変更するときに"revision"を自動で割り振るため構成から削除

    // 環境変数の変更
    service_template.containers[0].env = [ { name: 'key1', value: 'value1', values: 'value' }, { name: 'env', value: 'dev', values: 'value' } ]

    // 最大インスタンス数の変更
    service_template.scaling.minInstanceCount = 1;

    // 構成を更新
    const new_service_configuration = await callUpdateService(service_name, service_template);
    console.log('Cloud RUNの構成変更済みの構成');
    console.log(new_service_configuration);

    console.log('Cloud RUNの構成変更の実行完了');
}


main();
実行コマンド
npm start

実行すると、Cloud RUNの構成が変更されます。

おわり。

Discussion