Cloud Run을 사용한 Pub/Sub to BigQuery 파이프라인 구축

김민형·2022년 10월 4일
0

GCP - Data

목록 보기
37/43

아키텍처

Cloud Run

완전 관리형 서버리스 플랫폼에서 원하는 언어(Go, Python, 자바, Node.js, .NET)를 사용하여 확장 가능하고 컨테이너화된 앱을 빌드하고 배포할 수 있는 제품이다.
즉, 도커같은 컨테이너만 준비해둔다면 매우 쉽게 해당 어플리케이션을 배포할 수 있는 것이다.

Pub/Sub to BigQuery 파이프라인을 컨테이너를 통해 배포해볼 건데, 여기선 faker라는 자바스크립트 패키지를 사용해 가짜 거래데이터를 생성하여 Pub/Sub에 넣어줄 것이다.

사전 세팅

faker패키지를 통해 만들어줄 가짜 데이터의 스키마와 동일한 스키마를 가진 테이블을 생성해준다.

스키마를 가진 Pub/Sub 주제와 구독을 하나 만들어준다.
BigQuery 구독을 생성할 것이므로 기본 구독을 생성지 않을 것이다.

스키마

{
  "type": "record",
  "name": "transaction_record",
  "fields": [
    {
      "name": "account",
      "type": "string"
    },
    {
      "name": "accountName",
      "type": "string"
    },
    {
      "name": "amount",
      "type": "string"
    },
    {
      "name": "creditCardNumber",
      "type": "string"
    },
    {
      "name": "currencyCode",
      "type": "string"
    },
    {
      "name": "pin",
      "type": "string"
    },
    {
      "name": "transactionType",
      "type": "string"
    }
  ]
}

Artifact Registry 생성

생성 완료

트러블슈팅

참고한 블로그에서 설명이 부족한 부분이 많았고 코드에도 빠진 부분이 좀 있었다.
때문에 트러블슈팅을 하며 진행했고, 그 과정이 포함되어 있다.

작업 폴더를 하나 생성해주고 안에 아래의 파일들을 넣는다.

index.js

const { faker } = require("@faker-js/faker");
const { PubSub } = require("@google-cloud/pubsub");

// dotenv란 .env라는 파일을 환경변수 파일로 사용할 수 있게 해주는 모듈
const dotenv = require("dotenv");

const values = dotenv.config();

// Faker JS 라이브러리를 사용해서 가짜 거래데이터 생성
const generateData = () => {
  const account = faker.finance.account(8);
  const accountName = faker.finance.accountName();
  const amount = faker.finance.amount(5, 1000, 2, "$");
  const creditCardNumber = faker.finance.creditCardNumber();
  const currencyCode = faker.finance.currencyCode();
  const pin = faker.finance.pin();
  const transactionType = faker.finance.transactionType();

  const data = JSON.stringify({
    account: account,
    accountName: accountName,
    amount: amount,
    creditCardNumber: creditCardNumber,
    currencyCode: currencyCode,
    pin: pin,
    transactionType: transactionType,
  });
  return data;
};

// PubSub 주제로 가짜데이터 게시
const publishMessage = async () => {
  const topicName = process.env.TOPIC_NAME;
  const projectId = process.env.PROJECT_ID;

  const pubsubClient = new PubSub({ projectId });
  for (i = 0; i < 10000; i++) {
    const data = generateData();
    const dataBuffer = Buffer.from(data);

    try {
      const messageId = await pubsubClient.topic(topicName).publish(dataBuffer);
      console.log(`Message ID ${messageId} published`);
    } catch (error) {
      console.error(`Received error while publishing: ${error.message}`);
      process.exitCode = 1;
    }
  }
};
publishMessage();

Dockerfile

FROM node:latest
LABEL AUTHOR="minbroK"
COPY index.js package.json .env /
RUN npm install
CMD [ "node", "index.js" ]

.env

TOPIC_NAME=<만들어준 Pub/Sub 주제 이름>
PROJECT_ID=<프로젝트 ID>

package.json 생성하기 위해 npm init을 해준 후, 컨테이너를 빌드한다.

npm init -y
gcloud builds submit --tag <Image URL>/<Image name:버전>

Image URL은 내가 만들어준 Artifact Registry의 경로라고 생각하면 된다.

이렇게 하면 Cloud Build에 컨테이너가 빌드된다.

Cloud Run 서비스 생성시 컨테이너 이미지 URL을 선택할 때 아래와 같이 배포된 이미지와 1버전이 뜨는 것을 확인할 수 있다.

하지만 Cloud Run으로 이 상태로만 배포해주면 아래와 같이 에러가 난다.

링크를 따라가서 로그를 확인해보면 두 가지 에러가 난다.

  • 1. 필요한 모듈이 존재하지 않는 것.
  • 2. 8080포트 관련 에러

1. 필요한 모듈 설치

index.js에서 사용하는 모듈들을 설치하지 않았던 것이다.

# faker 모듈 설치
npm install @faker-js/faker --save-dev

# pub/sub 모듈 설치
npm install @google-cloud/pubsub

# dotenv 모듈 설치
npm install dotenv

# express 모듈 설치
npm install --save express@4

이렇게 설치를 해주면 node_modules이 생기게 되고 기존 package.json이 변경되므로 package-lock.json이라는 파일이 하나 생길 것이다.

package-lock.json
dependencies에 설치해준 패키지들이 들어가있는 것을 확인할 수 있고, 각 패키지들에 대한 정보는 아래 사진의 faker처럼 모듈 정보에서 확인할 수 있다.

Dockerfile에 COPY부분에 package-lock.json을 추가해주자.

package.json과 package-lock.json 차이

2. 8080포트 관련 에러
또한 위에 Cloud Run에서 에러난 사진을 자세히 보면 아래와 같을 것이다.

The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.

이는 로컬의 $PORT값을 통해 HTTP요청을 리슨해야 컨테이너가 돌아간다는 뜻이다. 즉, index.js코드에서 컨테이너 포트 8080을 열어주는 작업이 필요하다는 것이었다.

Cloud Run 8080포트 에러 트러블슈팅 참고1

express 모듈을 설치해준 이유가 바로 이 때문이다.
express 모듈을 사용하면 해당 앱으로 HTTP Request가 올 때 내부에서 따로 매핑해서 사용할 포트를 지정하고 열어줄 수 있다.
즉, Cloud Run을 통해 배포되는 컨테이너는 default로 8080포트를 통해 통신하는데 그 포트를 열어줄 수 있는 것이다.

아래의 코드를 추가해줘야 한다.

index.js(추가)

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

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

같은 경로에 컨테이너 환경변수가 저장된 .env에 $PORT를 사용한다.
.env에 PORT=8080을 추가해주자.

Cloud Run 8080포트 에러 트러블슈팅 참고2

Cloud Run 8080포트 에러 트러블슈팅 참고3

배포

위의 파일들을 다시 한 번 빌드해주고 이제 Cloud Run으로 배포하면 에러가 나지 않을 것이다.

우선 test이므로 공개 API로 설정하여 배포해준다.

배포 성공

처음에 만들어준 테이블에 데이터가 잘 들어와있는 것을 확인할 수 있다.

컨테이너 Build를 할 때 Cloud Build용 버킷이 생성되고 그 소스가 여기 저장된다.
(사실 블로그를 참고해서 했지만 설명이 제대로 안나와있고 코드도 빠진 부분이 좀 있어서 트러블슈팅하느라 빌드를 많이했다..)

[Cloud Run을 사용한 Pub/Sub to BigQuery 파이프라인 구축 참고]
https://medium.com/google-cloud/simplify-streaming-elt-pipeline-using-bigquery-subscriptions-with-pub-sub-b3c4fb69e5f4

profile
Solutions Architect (rlaalsgud97@gmail.com)

0개의 댓글