Cloud Run의 Node.js 애플리케이션을 PostgreSQL용 Cloud SQL 데이터베이스에 연결하는 방법

1. 개요

Cloud SQL Node.js 커넥터는 Node.js 애플리케이션을 Cloud SQL 데이터베이스에 안전하게 연결하는 가장 쉬운 방법입니다. Cloud Run은 HTTP 요청을 통해 호출 가능한 스테이트리스(Stateless) 컨테이너를 실행할 수 있는 완전 관리형 서버리스 플랫폼입니다. 이 Codelab에서는 IAM 인증을 사용하여 서비스 계정으로 Cloud Run의 Node.js 애플리케이션을 PostgreSQL용 Cloud SQL 데이터베이스에 안전하게 연결하는 방법을 보여줍니다.

학습할 내용

이 실습에서는 다음 작업을 진행하는 방법을 학습합니다.

  • PostgreSQL 데이터베이스용 Cloud SQL 인스턴스 만들기
  • Cloud Run에 Node.js 애플리케이션 배포
  • Cloud SQL Node.js 커넥터 라이브러리를 사용하여 애플리케이션을 데이터베이스에 연결

기본 요건

  • 이 실습에서는 Cloud 콘솔 및 Cloud Shell 환경에 익숙하다고 가정합니다.

2. 시작하기 전에

Cloud 프로젝트 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Google 계정이 없다면 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔은 고유한 문자열을 자동으로 생성합니다. 일반적으로는 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 다른 임의 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스 또는 전체 프로젝트를 삭제하면 됩니다. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

환경 설정

검색창 오른쪽에 있는 아이콘을 클릭하여 Cloud Shell을 활성화합니다.

ecdc43ada29e91b.png

Cloud Shell에서 API를 사용 설정합니다.

gcloud services enable compute.googleapis.com sqladmin.googleapis.com \
  run.googleapis.com artifactregistry.googleapis.com \
  cloudbuild.googleapis.com servicenetworking.googleapis.com

승인을 요청하는 메시지가 표시되면 '승인'을 클릭하여 계속합니다.

6356559df3eccdda.png

이 명령어를 완료하는 데 몇 분이 걸릴 수 있지만 결국 다음과 비슷한 성공 메시지가 표시됩니다.

Operation "operations/acf.p2-327036483151-73d90d00-47ee-447a-b600-a6badf0eceae" finished successfully.

3. 서비스 계정 설정

Cloud SQL에 연결할 수 있는 올바른 권한이 있도록 Cloud Run에서 사용할 Google Cloud 서비스 계정을 만들고 구성합니다.

  1. 다음과 같이 gcloud iam service-accounts create 명령어를 실행하여 새 서비스 계정을 만듭니다.
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. 다음과 같이 gcloud projects add-iam-policy-binding 명령어를 실행하여 방금 만든 Google Cloud 서비스 계정에 Cloud SQL 클라이언트 역할을 추가합니다. Cloud Shell에서 ${GOOGLE_CLOUD_PROJECT} 표현식은 프로젝트 이름으로 대체됩니다. 원하는 경우 수동으로 교체할 수도 있습니다.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.client"
    
  3. 다음과 같이 gcloud projects add-iam-policy-binding 명령어를 실행하여 방금 만든 Google Cloud 서비스 계정에 Cloud SQL 인스턴스 사용자 역할을 추가합니다.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.instanceUser"
    
  4. 다음과 같이 gcloud projects add-iam-policy-binding 명령어를 실행하여 방금 만든 Google Cloud 서비스 계정에 로그 작성자 역할을 추가합니다.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/logging.logWriter"
    

4. Cloud SQL 설정

gcloud sql instances create 명령어를 실행하여 Cloud SQL 인스턴스를 만듭니다.

  • --database-version: 데이터베이스 엔진 유형 및 버전입니다. 지정하지 않으면 API 기본값이 사용됩니다. 현재 사용 가능한 버전을 보려면 gcloud 데이터베이스 버전 문서를 참고하세요.
  • --cpu: 머신에 사용하려는 코어 수입니다.
  • --memory: 머신에 사용하려는 메모리 양을 나타내는 정수 값입니다. 크기 단위를 제공해야 합니다 (예: 3072MB 또는 9GB). 단위를 지정하지 않으면 GB로 간주됩니다.
  • --region: 인스턴스의 리전 위치입니다 (예: us-central1, asia-east1, us-east1).
  • --database-flags: 플래그를 설정할 수 있습니다. 이 경우 앞에서 만든 서비스 계정을 사용하여 Cloud Run이 Cloud SQL에 연결할 수 있도록 cloudsql.iam_authentication를 사용 설정합니다.
    gcloud sql instances create quickstart-instance \
      --database-version=POSTGRES_18 \
      --tier=db-custom-1-3840 \
      --region=us-central1 \
      --edition=ENTERPRISE \
      --database-flags=cloudsql.iam_authentication=on
    

이 명령어를 완료하는 데 몇 분이 걸릴 수 있습니다.

gcloud sql databases create 명령어를 실행하여 quickstart-instance 내에 Cloud SQL 데이터베이스를 만듭니다.

gcloud sql databases create quickstart_db \
  --instance=quickstart-instance

앞서 만든 서비스 계정으로 데이터베이스에 액세스할 수 있도록 PostgreSQL 데이터베이스 사용자를 만듭니다.

gcloud sql users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
  --instance=quickstart-instance \
  --type=cloud_iam_service_account \
  --database-roles=postgres

경고: 프로덕션 애플리케이션에서는 --database-roles=postgres를 사용하지 마세요. 이 실습의 코드에서 프로그래매틱 방식으로 테이블을 만들고 삭제하는 데 필요한 권한을 제공하는 데 사용됩니다.

5. 애플리케이션 준비

HTTP 요청에 응답하는 Node.js 애플리케이션을 준비합니다.

  1. Cloud Shell에서 helloworld이라는 새 디렉터리를 만든 다음 해당 디렉터리로 변경합니다.
    mkdir helloworld
    cd helloworld
    
  2. package.json 파일을 모듈로 초기화합니다.
    npm init -y
    npm pkg set type="module"
    npm pkg set main="index.mjs"
    npm pkg set scripts.start="node index.mjs"
    
  3. Cloud SQL Node.js 커넥터 종속 항목을 설치합니다.
    npm install @google-cloud/cloud-sql-connector
    
  4. PostgreSQL 데이터베이스와 상호작용하려면 pg를 설치합니다.
    npm install pg
    
  5. 들어오는 http 요청을 수락하도록 express를 설치합니다.
    npm install express
    
  6. 애플리케이션 코드를 사용하여 index.mjs 파일을 만듭니다. 이 코드는 다음 작업을 할 수 있습니다.
    • HTTP 요청 수락
    • 데이터베이스에 연결
    • HTTP 요청 시간을 데이터베이스에 저장
    • 마지막 5개 요청의 시간을 반환합니다.
    Cloud Shell에서 다음 명령어를 실행합니다.
    cat > index.mjs << "EOF"
    import express from 'express';
    import pg from 'pg';
    import {Connector} from '@google-cloud/cloud-sql-connector';
    
    const {Pool} = pg;
    
    const connector = new Connector();
    const clientOpts = await connector.getOptions({
        instanceConnectionName: process.env.INSTANCE_CONNECTION_NAME,
        authType: 'IAM'
    });
    
    const pool = new Pool({
        ...clientOpts,
        user: process.env.DB_USER,
        database: process.env.DB_NAME
    });
    
    const app = express();
    
    app.get('/', async (req, res) => {
      await pool.query('INSERT INTO visits(created_at) VALUES(NOW())');
      const {rows} = await pool.query('SELECT created_at FROM visits ORDER BY created_at DESC LIMIT 5');
      console.table(rows); // prints the last 5 visits
      res.send(rows);
    });
    
    const port = parseInt(process.env.PORT) || 8080;
    app.listen(port, async () => {
      console.log('process.env: ', process.env);
      await pool.query(`CREATE TABLE IF NOT EXISTS visits (
        id SERIAL NOT NULL,
        created_at timestamp NOT NULL,
        PRIMARY KEY (id)
      );`);
      console.log(`helloworld: listening on port ${port}`);
    });
    
    EOF
    

이 코드는 PORT 환경 변수로 정의한 포트를 리슨하는 기본 웹 서버를 생성합니다. 이제 애플리케이션을 배포할 준비가 되었습니다.

6. Cloud Run 애플리케이션 배포

아래 명령어를 실행하여 애플리케이션을 Cloud Run에 배포합니다.

  • --region: 인스턴스의 리전 위치입니다 (예: us-central1, asia-east1, us-east1).
  • --source: 배포할 소스 코드입니다. 이 경우 .는 현재 폴더 helloworld의 소스 코드를 참조합니다.
  • --set-env-vars: 애플리케이션이 Cloud SQL 데이터베이스로 향하도록 애플리케이션에서 사용하는 환경 변수를 설정합니다.
  • --service-account: 이 Codelab 시작 시 생성된 Cloud SQL 데이터베이스에 연결할 권한이 있는 서비스 계정에 Cloud Run 배포를 연결합니다.
  • --allow-unauthenticated: 인증되지 않은 요청을 허용하여 인터넷에서 애플리케이션에 액세스할 수 있도록 합니다.
gcloud run deploy helloworld \
  --region=us-central1 \
  --source=. \
  --set-env-vars INSTANCE_CONNECTION_NAME="${GOOGLE_CLOUD_PROJECT}:us-central1:quickstart-instance" \
  --set-env-vars DB_NAME="quickstart_db" \
  --set-env-vars DB_USER="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam" \
  --service-account="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
  --allow-unauthenticated

메시지가 표시되면 yEnter를 눌러 계속 진행할지 확인합니다.

Do you want to continue (Y/n)? y

몇 분 후 애플리케이션에서 방문할 URL을 제공합니다.

URL로 이동하여 애플리케이션이 작동하는지 확인합니다. URL을 방문하거나 페이지를 새로고침할 때마다 최근 5건의 방문이 JSON으로 반환됩니다.

7. 축하합니다

Cloud SQL에서 실행되는 PostgreSQL 데이터베이스에 연결할 수 있는 Node.js 애플리케이션을 Cloud Run에 배포했습니다.

학습한 내용

  • PostgreSQL용 Cloud SQL 데이터베이스 만들기
  • Cloud Run에 Node.js 애플리케이션 배포
  • Cloud SQL Node.js 커넥터를 사용하여 애플리케이션을 Cloud SQL에 연결

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요. 전체 프로젝트를 삭제하려면 다음을 실행하면 됩니다.

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}