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

1. 概要

はじめに

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

技術的概要

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

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

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

ユースケース

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

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

この 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

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

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 リポジトリを作成する

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

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

次のコマンドを実行して、Ingress コンテナのイメージをビルドできるようになりました。

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

次のコマンドを実行して、Ingress コンテナのイメージをビルドできるようになりました。

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 コンテナは共有ボリューム上のファイルに書き込みます。サイドカーがファイルを読み取り、その内容を Ingress コンテナに返します。

まず、Ingress コンテナコードを更新します。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}`);
});

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

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

Volume を共有するには、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 のコンソール(https://console.cloud.google.com/run/)に移動し、sidecar-codelab サービス(別の名前を使用している場合は $SERVICE_NAME)を削除します。

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