建立使用補充容器的 Cloud Run 服務

1. 總覽

簡介

在本程式碼研究室中,您將學習如何部署使用多個容器Cloud Run 服務。您將建立 node.js 應用程式做為 Cloud Run 輸入容器,以及做為補充資訊使用的 node.js 應用程式。

技術總覽

在 Cloud Run 執行個體中使用多個容器時,會有一個容器做為網路輸入的主要容器。一或多個額外容器稱為「補充容器」。

不同容器可透過以下兩種方式進行通訊:

  1. 容器會共用 localhost 網路介面,因此所有容器都能監聽通訊埠,例如:localhost:port.
  2. 您也可以使用記憶體內的磁碟區,將這些磁碟區掛接至容器以共用檔案。

用途

由於 Cloud Run 執行個體中的所有容器都共用 localhost 網路介面,因此您可以在主要容器前方使用補充資訊透過 Proxy 傳送要求。這類 Proxy 可攔截要求並轉送至適當的端點,在用戶端和伺服器之間提高應用程式流量的效率,提供額外的抽象層。例如,您可以使用 DockerHub 中的官方 Nginx 映像檔 (如這裡所示)。

多個容器可以透過共用磁碟區共用檔案,因此您可以新增各種補充資訊應用程式到您的服務。舉例來說,您可以檢測 Cloud Run 服務,以便使用 OpenTelemetry 等自訂代理程式來匯出記錄檔、指標和追蹤記錄 (OpenTelemetry 範例)。另一個例子是使用補充資訊連結至 Cloud Spanner PostgreSQL 資料庫 (Cloud Spanner Postgress 範例)。

本程式碼研究室的範例

在本程式碼研究室中,首先要部署 Cloud Run 服務,其輸入容器透過 localhost 通訊埠與補充容器進行通訊。接著,請更新 Ingress 容器和補充資訊,透過磁碟區掛接來分享檔案。

課程內容

  • 如何建立使用補充容器的容器
  • Ingress 容器如何使用 localhost 與補充容器通訊
  • Ingress 容器和補充資訊可以透過掛接的磁碟區如何共用檔案

2. 設定和需求

必要條件

啟用 Cloud Shell

  1. 在 Cloud 控制台中,按一下「啟用 Cloud Shell」圖示 d1264ca30785e435.png

cb81e7c8e34bc8d.png

如果您是第一次啟動 Cloud Shell,系統會顯示中繼畫面,說明這項服務的內容。如果系統顯示中繼畫面,請按一下「繼續」

d95252b003979716.png

佈建並連線至 Cloud Shell 只需幾分鐘的時間。

7833d5e1c5d18f54.png

這個虛擬機器已載入所有必要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。在本程式碼研究室中,您的大部分作業都可透過瀏覽器完成。

連線至 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 應用程式

設定環境變數

在本程式碼研究室中,您將建立幾個環境變數,改善本程式碼研究室中使用的 gcloud 指令可讀性。

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

SERVICE_NAME=sidecar-codelab
REPO_NAME=sidecar-codelab

建立 ArtifactRegistry 存放區來存放容器映像檔

您可以在 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}`);
});

為輸入容器建立 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. 建立補充資訊應用程式

在本節中,您將建立第二個 node.js 應用程式,用來做為 Cloud Run 服務中的補充容器。

前往補充資訊目錄。

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

部署完成後,將服務網址儲存在環境變數中。

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

5. 呼叫 Cloud Run 服務

您現在可以提供識別權杖來呼叫服務。

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 容器程式碼。前往輸入目錄。

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

使用下列指令更新 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

您現在可以提供識別權杖來呼叫服務。

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

結果應該會與下方的範例輸出內容類似:

The sidecar says: the ingress container created this file.

7. 恭喜!

恭喜您完成本程式碼研究室!

建議您詳閱 Cloud Run 的說明文件,特別是部署多容器及使用記憶體內磁碟區掛接

涵蓋內容

  • 如何建立使用補充容器的容器
  • Ingress 容器如何使用 localhost 與補充容器通訊
  • Ingress 容器和補充車輛如何共用已掛接的磁碟區

8. 清除所用資源

為避免產生意外費用 (舉例來說,如果不小心叫用這個 Cloud 函式的次數超出免費方案的每月 Cloud Run 叫用分配數量),您可以刪除 Cloud Run 服務,或刪除步驟 2 建立的專案。

如要刪除 Cloud 函式,請前往 Cloud 函式 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 來查看可用專案的清單。