サイドカーを使用して Cloud Run サービスを作成する

1. 概要

はじめに

この Codelab では、複数のコンテナを使用する Cloud Run サービスをデプロイする方法を学びます。Cloud Run 上のイングレコンテナとして使用される Node.js アプリと、サイドカーとして使用される追加の Node.js アプリを作成します。

技術的概要

Cloud Run インスタンス内で複数のコンテナを使用する場合、1 つのコンテナがウェブ上り(内向き)のメイン コンテナとして使用されます。1 つ以上の追加コンテナはサイドカーと呼ばれます。

複数のコンテナが相互に通信する方法は 2 つあります。

  1. コンテナは localhost ネットワーク インターフェースを共有するため、すべてのコンテナがポート(localhost:port など)をリッスンできます。
  2. インメモリ ボリュームを使用して、コンテナにマウントしてファイルを共有することもできます。

ユースケース

Cloud Run インスタンス内のすべてのコンテナは localhost ネットワーク インターフェースを共有するため、メインコンテナの前にサイドカーを使用してリクエストをプロキシできます。このようなプロキシは抽象化レイヤとしての役割を果たします。具体的には、リクエストをインターセプトして適切なエンドポイントに転送することで、クライアントとサーバー間でアプリケーションへのトラフィックを効率よく流すために役立ちます。たとえば、DockerHub の公式の Nginx イメージを使用できます(こちらを参照)。

複数のコンテナは共有ボリュームを介してファイルを共有することで通信できるため、サービスにさまざまなサイドカー アプリケーションを追加します。たとえば、Cloud Run サービスをインストルメント化して、OpenTelemetry などのカスタム エージェントを使用してログ、指標、トレースをエクスポートできます(OpenTelemetry の例)。別の例として、サイドカーを使用して Cloud Spanner PostgreSQL データベースに接続する方法があります(Cloud Spanner Postgress の例)。

この Codelab の例

この Codelab では、まず、Ingress コンテナが localhost ポートを介してサイドカーと通信する Cloud Run サービスをデプロイします。次に、ボリューム マウントを介してファイルを共有するように、Ingress コンテナとサイドカーを更新します。

学習内容

  • サイドカーを使用するコンテナの作成方法
  • localhost を使用して Ingress コンテナがサイドカーと通信する方法
  • マウントされたボリュームを介して Ingress コンテナとサイドカーがファイルを共有する方法

2. 設定と要件

前提条件

Cloud Shell をアクティブにする

  1. Cloud Console で、[Cloud Shell をアクティブにする] d1264ca30785e435.png をクリックします。

cb81e7c8e34bc8d.png

Cloud Shell を初めて起動する場合は、その内容を説明する中間画面が表示されます。中間画面が表示された場合は、[続行] をクリックします。

d95252b003979716.png

すぐにプロビジョニングが実行され、Cloud Shell に接続されます。

7833d5e1c5d18f54.png

この仮想マシンには、必要な開発ツールがすべて用意されています。仮想マシンは Google Cloud で稼働し、永続的なホーム ディレクトリが 5 GB 用意されているため、ネットワークのパフォーマンスと認証が大幅に向上しています。このコードラボで行う作業のほとんどはブラウザから実行できます。

Cloud Shell に接続すると、認証が完了しており、プロジェクトに各自のプロジェクト ID が設定されていることがわかります。

  1. Cloud Shell で次のコマンドを実行して、認証されたことを確認します。
gcloud auth list

コマンド出力

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project

コマンド出力

[core]
project = <PROJECT_ID>

上記のようになっていない場合は、次のコマンドで設定できます。

gcloud config set project <PROJECT_ID>

コマンド出力

Updated property [core/project].

3. Ingress アプリを作成する

環境変数の設定

この Codelab では、この Codelab で使用する gcloud コマンドの可読性を高めるために、いくつかの環境変数を作成します。

REGION=<YOUR-REGION>
PROJECT_ID=<YOUR-PROJECT-ID>

SERVICE_NAME=sidecar-codelab
REPO_NAME=sidecar-codelab

コンテナ イメージを保持する ArtifactRegistry リポジトリを作成する

この Codelab では、Artifact Registry にリポジトリを作成してコンテナ イメージを保存できます。

gcloud artifacts repositories create $REPO_NAME --repository-format=docker \
--location=$REGION --description="sidecar codelab"

次に、次の内容の package.json ファイルを作成します。

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node ingress.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

次に、次の内容の ingress.js という名前のファイルを作成します。

const express = require('express');
const app = express();
const axios = require("axios");

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`Ingress container listening on port ${port}`);
});

Ingress コンテナの Dockerfile を作成する

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=8080
CMD [ "npm", "start" ]

また、Ingress コンテナ用の `.dockerignore` ファイルを作成します。

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

次のコマンドを実行して、上り(内向き)コンテナのイメージをビルドします。

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

4. サイドカー アプリを作成する

このセクションでは、Cloud Run サービスでサイドカーとして使用される 2 番目の node.js アプリを作成します。

サイドカー ディレクトリに移動します。

cd ../sidecar

次の内容の package.json ファイルを作成します。

{
  "name": "sidecar-codelab",
  "version": "1.0.0",
  "private": true,
  "description": "demonstrates how to use sidecars in cloud run",
  "main": "index.js",
  "author": "Google LLC",
  "license": "Apache-2.0",
  "scripts": {
    "start": "node sidecar.js"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "express": "^4.18.2"
  }
}

次に、次の内容の sidecar.js という名前のファイルを作成します。

const express = require('express');
const app = express();

app.get('/', async (req, res) => {
    res.send("Hello ingress container! I'm the sidecar.");
});

const port = parseInt(process.env.PORT || 5000);
app.listen(port, () => {
    console.log(`Sidecar container listening on port ${port}`);
});

サイドカー コンテナ用の Dockerfile を作成する

FROM node:20.10.0-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
ENV PORT=5000
CMD [ "npm", "start" ]

また、サイドカー コンテナ用の `.dockerignore` ファイルを作成します。

# Exclude locally installed dependencies
node_modules/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

次のコマンドを実行して、上り(内向き)コンテナのイメージをビルドします。

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

Cloud Run サービスをデプロイする

yaml ファイルを使用して Cloud Run サービスをデプロイします。

親ディレクトリに移動します。

cd ..

次の内容のファイルを、sidecar-codelab.yaml という名前で作成します。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"

次のコマンドを使用してサービスをデプロイします。ボリューム マウントは公開プレビュー版であるため、gcloud beta を使用する必要があります。

gcloud beta run services replace sidecar-codelab.yaml

デプロイしたら、サービス URL を環境変数に保存します。

SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --platform managed --region $REGION --format 'value(status.url)') 

5. Cloud Run サービスを呼び出す

これで、ID トークンを指定してサービスを呼び出すことができます。

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

結果は、次の出力例のようになります。

The sidecar says: Hello ingress container! I'm the sidecar.

6. ボリューム マウントを介してファイルを共有する

このセクションでは、ボリューム マウントを介してファイルを共有するようにコンテナを更新します。この例では、上り(内向き)コンテナは共有ボリューム上のファイルに書き込みます。サイドカーはファイルを読み取り、その内容を上り(内向き)コンテナに返します。

まず、上り(内向き)コンテナ コードを更新します。ingress ディレクトリに移動します。

cd ../ingress

ingress.js ファイルの内容を次のように置き換えます。

const express = require('express');
const app = express();
const fs = require('fs');
const axios = require("axios");

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

try {
    fs.writeFileSync(`${path}/${filename}`, "The ingress container created this file.");
} catch (err) {
    console.error(err);
}

app.get('/', async (req, res) => {

    let response = await axios.get("http://localhost:5000");

    res.send("The sidecar says: " + response.data);
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`Ingress container listening on port ${port}`);
});

次のコマンドを実行して、上り(内向き)コンテナの新しいイメージをビルドします。

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/ingress:latest

サイドカー ディレクトリに移動します。

cd ../sidecar

sidecar.js を次の内容で更新します。

const express = require('express');
const app = express();
const fs = require('fs');

const filename = "test.txt"

let path = "/my-volume-mount";
app.use(path, express.static(path));

async function readFile() {
    try {
        return await fs.readFileSync(`${path}/${filename}`, { encoding: 'utf8' });
    } catch (err) {
        console.log(err);
    }
}

app.get('/', async (req, res) => {
    let contents = await readFile();
    res.send(contents);
});

const port = parseInt(process.env.PORT || 5000);
app.listen(port, () => {
    console.log(`Sidecar container listening on port ${port}`);
});

次のコマンドを実行して、サイドカー コンテナの新しいイメージをビルドします。

gcloud builds submit --tag $REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/sidecar:latest

ボリュームを共有するには、次のように sidecar-codelab.yaml を更新します。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
  name: sidecar-codelab
  labels:
    cloud.googleapis.com/location: "<YOUR_REGION>"
spec:
  template:
    spec:
      containers:
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/ingress:latest"
          ports:
            - containerPort: 8080
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
        - image: "<YOUR_REGION>-docker.pkg.dev/<YOUR_PROJECT_ID>/sidecar-codelab/sidecar:latest"
          env:
            - name: PORT
              value: "5000"
          volumeMounts:
            - mountPath: /my-volume-mount
              name: in-memory-1
      volumes:
        - emptyDir:
            medium: Memory
          name: in-memory-1

更新された sidecar-codelab.yaml ファイルをデプロイする

gcloud beta run services replace sidecar-codelab.yaml

これで、ID トークンを指定してサービスを呼び出すことができます。

curl -X GET -H "Authorization: Bearer $(gcloud auth print-identity-token)" ${SERVICE_URL}

結果は、次の出力例のようになります。

The sidecar says: the ingress container created this file.

7. 完了

以上で、この Codelab は完了です。

Cloud Run のドキュメント(特にマルチコンテナのデプロイとインメモリ ボリューム マウントの使用)を確認することをおすすめします。

学習した内容

  • サイドカーを使用するコンテナの作成方法
  • localhost を使用して Ingress コンテナがサイドカーと通信する方法
  • Ingress コンテナとサイドカーがマウントされたボリュームを共有する方法

8. クリーンアップ

誤って課金されないように(たとえば、この Cloud Functions が 無料枠の Cloud Run 呼び出しの月間割り当てよりも多く呼び出された場合など)、Cloud Run サービスを削除するか、ステップ 2 で作成したプロジェクトを削除します。

Cloud Functions を削除するには、Cloud Functions Cloud コンソール(https://console.cloud.google.com/run/)に移動し、sidecar-codelab サービス(別の名前を使用した場合は $SERVICE_NAME)を削除します。

プロジェクト全体を削除する場合は、https://console.cloud.google.com/cloud-resource-manager に移動し、ステップ 2 で作成したプロジェクトを選択して、[削除] を選択します。プロジェクトを削除した場合は、Cloud SDK でプロジェクトを変更する必要があります。gcloud projects list を実行すると、使用可能なすべてのプロジェクトのリストを表示できます。