사이드카로 Cloud Run 서비스 만들기

1. 개요

소개

이 Codelab에서는 여러 컨테이너를 사용하는 Cloud Run 서비스를 배포하는 방법을 알아봅니다. Cloud Run 인그레스 컨테이너로 사용할 node.js 앱과 사이드카로 사용할 추가 node.js 앱을 만듭니다.

기술 개요

Cloud Run 인스턴스 내에서 여러 컨테이너를 사용하는 경우 하나의 컨테이너가 웹 인그레스의 기본 컨테이너로 사용됩니다. 하나 이상의 추가 컨테이너를 사이드카라고 합니다.

여러 컨테이너가 서로 통신하는 방법에는 두 가지가 있습니다.

  1. 컨테이너는 localhost 네트워크 인터페이스를 공유하므로 모든 컨테이너는 포트를 리슨할 수 있습니다. 예를 들어 localhost:port.
  2. 또한 인메모리 볼륨을 사용하고 컨테이너에 마운트하여 파일을 공유할 수도 있습니다.

사용 사례

Cloud Run 인스턴스 내의 모든 컨테이너는 localhost 네트워크 인터페이스를 공유하므로 주 컨테이너 앞에 사이드카를 사용하여 요청을 프록시할 수 있습니다. 이러한 프록시는 요청을 가로채서 적절한 엔드포인트로 전달하여 클라이언트와 서버 간의 애플리케이션에 대한 보다 효율적인 트래픽 흐름을 위한 추가 추상화 계층을 제공할 수 있습니다. 예를 들어 DockerHub의 공식 Nginx 이미지를 사용할 수 있습니다 (여기 참고).

여러 컨테이너가 공유 볼륨을 통해 파일을 공유하여 통신할 수 있으므로 서비스에 다양한 사이드카 애플리케이션을 추가합니다. 예를 들어 Cloud Run 서비스를 계측하여 OpenTelemetry와 같은 커스텀 에이전트를 사용해 로그, 측정항목, trace를 내보낼 수 있습니다 (OpenTelemetry 예시). 또 다른 예는 Cloud Spanner PostgreSQL 데이터베이스에 사이드카 연결을 사용하는 것입니다 (Cloud Spanner Postgress 예시).

이 Codelab의 예

이 Codelab에서는 먼저 인그레스 컨테이너가 localhost 포트를 통해 사이드카와 통신하는 Cloud Run 서비스를 배포합니다. 그런 다음 볼륨 마운트를 통해 파일을 공유하도록 인그레스 컨테이너와 사이드카를 업데이트합니다.

학습할 내용

  • 사이드카를 사용하는 컨테이너를 만드는 방법
  • 인그레스 컨테이너가 localhost를 사용하여 사이드카와 통신하는 방법
  • 인그레스 컨테이너와 사이드카가 마운트된 볼륨을 통해 파일을 공유하는 방법

2. 설정 및 요구사항

기본 요건

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화d1264ca30785e435.png를 클릭합니다.

cb81e7c8e34bc8d.png

Cloud Shell을 처음 시작하는 경우에는 무엇이 있는지 설명하는 중간 화면이 표시됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

d95252b003979716.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

7833d5e1c5d18f54.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 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. 인그레스 앱 만들기

환경 변수 설정

이 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}`);
});

인그레스 컨테이너용 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" ]

인그레스 컨테이너를 위한 ``.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 서비스에서 사이드카로 사용할 두 번째 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. 볼륨 마운트를 통해 파일 공유

이 섹션에서는 볼륨 마운트를 통해 파일을 공유하도록 컨테이너를 업데이트합니다. 이 예시에서 인그레스 컨테이너는 공유 볼륨의 파일에 씁니다. 사이드카가 파일을 읽고 그 콘텐츠를 인그레스 컨테이너로 다시 반환합니다.

먼저 인그레스 컨테이너 코드를 업데이트합니다. 인그레스 디렉터리로 이동합니다.

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를 사용하여 사이드카와 통신하는 방법
  • 인그레스 컨테이너와 사이드카가 마운트된 볼륨을 공유하는 방법

8. 삭제

실수로 인한 요금 청구를 방지하려면(예: 이 Cloud 함수가 무료 등급의 월별 Cloud Run 호출 할당보다 실수로 더 많이 호출되는 경우) Cloud Run 서비스를 삭제하거나 2단계에서 만든 프로젝트를 삭제합니다.

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를 실행하면 사용 가능한 모든 프로젝트의 목록을 볼 수 있습니다.