완전 관리형 서버리스 플랫폼에서 원하는 언어(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. 필요한 모듈 설치
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을 열어주는 작업이 필요하다는 것이었다.
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으로 배포하면 에러가 나지 않을 것이다.
우선 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