Cloud Run에서 프라이빗 CloudSQL에 연결

1. 개요

이 실습에서는 Cymbal Eats 메뉴 서비스를 만들고 RESTful API를 노출하여 메뉴 항목을 추가, 업데이트, 삭제, 나열합니다. Cloud Run에서 실행될 메뉴 서비스의 백엔드 데이터베이스로 Cloud SQL 데이터베이스를 만듭니다. Cloud Run은 Cloud SQL 데이터베이스와 동일한 VPC에 있지 않으므로 Cloud Run이 비공개 IP 주소를 통해 Cloud SQL과 통신할 수 있도록 서버리스 VPC 액세스 커넥터를 구성해야 합니다.

19c7b05f35789fda.png

학습할 내용

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

  • 비공개 VPC 네트워크 구성
  • 비공개 Postgres Cloud SQL 데이터베이스 만들기
  • 비공개 VPC에 CloudRun 연결
  • Cloud SQL 데이터베이스에 연결되는 서비스를 Cloud Run에 배포합니다.

2. 설정 및 요구사항

자습형 환경 설정

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

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 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

환경 설정

  1. 프로젝트 및 리소스 관련 환경 변수 만들기
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
export PROJECT_NAME=$(gcloud projects describe $PROJECT_ID --format='value(name)')
export REGION=us-east1
export MENU_SERVICE_NAME=menu-service

export SERVERLESS_VPC_CONNECTOR=cymbalconnector
export DB_INSTANCE_NAME=menu-catalog
export DB_INSTANCE_PASSWORD=password123
export DB_DATABASE=menu-db
export DB_USER=menu-user
export DB_PASSWORD=menupassword123
  1. 저장소를 클론하고 디렉터리로 이동합니다.
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git && cd cymbal-eats/menu-service
  1. 서비스 사용 설정
gcloud services enable \
    sqladmin.googleapis.com \
    run.googleapis.com \
    vpcaccess.googleapis.com \
    servicenetworking.googleapis.com

3. 비공개 액세스 구성

비공개 서비스 액세스는 VPC 네트워크와 Cloud SQL 인스턴스가 위치한 기본 Google Cloud VPC 네트워크 간의 VPC 피어링 링크로 제공됩니다. 비공개 연결을 사용하면 VPC 네트워크의 VM 인스턴스와 사용하는 서비스가 내부 IP 주소를 통해서만 통신할 수 있습니다. 비공개 서비스 액세스를 통해 사용 가능한 서비스에 액세스하기 위해 VM 인스턴스에는 인터넷 연결이나 외부 IP 주소가 필요하지 않습니다.

  1. IP 주소 범위 할당
gcloud compute addresses create google-managed-services-default \
    --global \
    --purpose=VPC_PEERING \
    --prefix-length=20 \
    --network=projects/$PROJECT_ID/global/networks/default

출력 예

Created [https://www.googleapis.com/compute/v1/projects/cymbal-eats-2-348215/global/addresses/google-managed-services-default].
  1. 비공개 연결을 만듭니다.
gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=google-managed-services-default \
    --network=default \
    --project=$PROJECT_ID

출력 예

Operation "operations/pssn.p24-528514492617-2f2b507f-e4e5-4d53-a4de-9ddaceb4e92f" finished successfully.

4. Cloud SQL 설정

Cloud SQL은 클라우드에서 PostgreSQL 및 MySQL 관계형 데이터베이스를 간편하게 설정, 유지, 관리할 수 있는 완전 관리형 데이터베이스 서비스입니다. 각 Cloud SQL 인스턴스는 Google Cloud 호스트 서버에서 실행되는 가상 머신 (VM)을 기반으로 합니다. 고가용성 옵션에는 기본 VM과 설정이 동일한 다른 영역의 대기 VM도 포함됩니다. 데이터베이스는 VM에 연결되는 영구 디스크라고 하는 확장 가능하고 내구성 있는 네트워크 스토리지 기기에 보관됩니다. Cloud SQL 인스턴스의 수명 동안 애플리케이션이 연결되는 IP 주소가 일정하게 유지되도록 각 VM에 고정 IP 주소가 할당됩니다.

219cb722c2dd1b82.png

비공개 IP 주소로 Postgres Cloud SQL 데이터베이스를 만듭니다.

데이터베이스 및 사용자 만들기

  1. 비공개 IP를 사용할 Postgres Cloud SQL 인스턴스 만들기
gcloud sql instances create $DB_INSTANCE_NAME \
    --project=$PROJECT_ID \
    --network=projects/$PROJECT_ID/global/networks/default \
    --no-assign-ip \
    --database-version=POSTGRES_12 \
    --cpu=2 \
    --memory=4GB \
    --region=$REGION \
    --root-password=${DB_INSTANCE_PASSWORD}

출력 예

Created [https://sqladmin.googleapis.com/sql/v1beta4/projects/cymbal1/instances/menu-instance].
NAME: menu-instance
DATABASE_VERSION: POSTGRES_12
LOCATION: us-east1-a
TIER: db-custom-2-4096
PRIMARY_ADDRESS: -
PRIVATE_ADDRESS: 10.8.80.5
STATUS: RUNNABLE
  1. 데이터베이스 인스턴스에 데이터베이스 추가
gcloud sql databases create $DB_DATABASE --instance=$DB_INSTANCE_NAME

출력 예

Created database [menu-db].
instance: menu-catalog
name: menu-db
project: cymbal1
  1. SQL 사용자 만들기
gcloud sql users create ${DB_USER} \
    --password=$DB_PASSWORD \
    --instance=$DB_INSTANCE_NAME

출력 예

Created user [menu-user].
  1. 데이터베이스 IP 주소 저장
export DB_INSTANCE_IP=$(gcloud sql instances describe $DB_INSTANCE_NAME \
    --format=json | jq \
    --raw-output ".ipAddresses[].ipAddress")
  1. Compute Engine 서비스 계정에 Cloud SQL 클라이언트 역할 추가
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role="roles/cloudsql.client"

출력 예

Updated IAM policy for project [cymbal1].
[...]

5. 서버리스 VPC

서버리스 VPC 액세스를 사용하면 Cloud Run, App Engine, Cloud Functions와 같은 서버리스 환경에서 Virtual Private Cloud 네트워크에 직접 연결할 수 있습니다. 서버리스 VPC 액세스를 구성하면 서버리스 환경에서 내부 DNS 및 내부 IP 주소 (RFC 1918 및 RFC 6598의 정의에 따름)를 사용하여 VPC 네트워크에 요청을 보낼 수 있습니다. 이러한 요청에 대한 응답에서도 내부 네트워크를 사용합니다.

Cloud Run 서비스를 위한 서버리스 VPC 액세스 커넥터를 만들어 Cloud SQL에 연결합니다.

19c7b05f35789fda.png

  1. Cloud SQL 인스턴스와 동일한 VPC 네트워크에 서버리스 VPC 액세스 커넥터를 만듭니다.
gcloud compute networks vpc-access connectors create ${SERVERLESS_VPC_CONNECTOR} \
    --region=${REGION} \
    --range=10.8.0.0/28

출력 예

Created connector [cymbalconnector].

6. Cloud Run에 배포

Docker 이미지를 빌드하여 Cloud Run에 배포하고 Cloud Run을 서버리스 VPC 커넥터에 연결하여 Cloud SQL 데이터베이스에 액세스합니다.

  1. Maven을 사용하여 애플리케이션 컴파일
./mvnw package -DskipTests

출력 예

[...]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  42.864 s
[INFO] Finished at: 2022-04-28T16:15:33Z
[INFO] ------------------------------------------------------------------------
  1. Docker 이미지를 빌드합니다.
docker build -f src/main/docker/Dockerfile.jvm \
    --tag gcr.io/$PROJECT_NAME/menu-service .

출력 예

[...]
Successfully built 4ef5d7a3befc
Successfully tagged gcr.io/cymbal1/menu-service:latest
  1. Container Registry에 Docker 이미지를 푸시합니다.
docker push gcr.io/$PROJECT_NAME/menu-service

출력 예

Using default tag: latest
The push refers to repository [gcr.io/cymbalsql/menu-service]
17b374963800: Pushed
d9a51c06430d: Pushed
fff5d2a2cfc9: Pushed
f21fceb558c6: Pushed
5ffbbbf218dd: Pushed
60609ec85f86: Layer already exists
f2c4302f03b8: Layer already exists
latest: digest: sha256:f64cb7c288dbf4ad9b12bd210c23c5aec1048dee040450ff2d9dbdf96e83a426 size: 1789
  1. 메뉴 서비스 배포:
gcloud run deploy $MENU_SERVICE_NAME \
    --image=gcr.io/$PROJECT_NAME/menu-service:latest \
    --region $REGION \
    --allow-unauthenticated \
    --set-env-vars DB_USER=$DB_USER \
    --set-env-vars DB_PASS=$DB_PASSWORD \
    --set-env-vars DB_DATABASE=$DB_DATABASE \
    --set-env-vars DB_HOST=$DB_INSTANCE_IP \
    --vpc-connector $SERVERLESS_VPC_CONNECTOR \
    --project=$PROJECT_ID \
    --quiet

출력 예

[...]
Done.
Service [menu-service] revision [menu-service-00002-xox] has been deployed and is serving 100 percent of traffic.
Service URL: https://menu-service-g2mfphytdq-uk.a.run.app

Secret Manager를 사용하여 SQL 사용자 인증 정보와 같은 민감한 정보를 저장하는 것이 좋습니다. Cloud Run을 사용하여 보안 비밀을 환경 변수로 전달하거나 볼륨으로 마운트할 수 있습니다.

  1. 매장 메뉴 서비스 URL:
MENU_SERVICE_URL=$(gcloud run services describe menu-service \
  --platform managed \
  --region $REGION \
  --format=json | jq \
  --raw-output ".status.url")
  1. 메뉴 서비스 URL 확인
echo $MENU_SERVICE_URL

출력 예

https://menu-service-g2mfphytdq-uk.a.run.app

7. 서비스 테스트

  1. POST 요청을 전송하여 새 메뉴 항목을 만듭니다.
curl -X POST "${MENU_SERVICE_URL}/menu" \
  -H 'Content-Type: application/json' \
  -d '{
       "itemImageURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
       "itemName": "Curry Plate",
       "itemPrice": 12.5,
       "itemThumbnailURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
       "spiceLevel": 3,
       "status": "Ready",
       "tagLine": "Spicy touch for your taste buds!!"
   }'

출력 예

{
    "id": 16,
    "createDateTime": "2022-04-28T18:14:04.17225",
    "itemImageURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
    "itemName": "Curry Plate",
    "itemPrice": 12.5,
    "itemThumbnailURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
    "spiceLevel": 3,
    "status": "Processing",
    "tagLine": "Spicy touch for your taste buds!!",
    "updateDateTime": "2022-04-28T18:14:04.172298"
}
  1. PUT 요청을 전송하여 메뉴 항목의 상태를 변경합니다.
curl -X PUT "${MENU_SERVICE_URL}/menu/1" \
  -H 'Content-Type: application/json' \
  -d '{"status": "Ready"}'

출력 예

{
    "id": 1,
    "createDateTime": "2022-04-28T17:21:02.369093",
    "itemImageURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
    "itemName": "Curry Plate",
    "itemPrice": 12.50,
    "itemThumbnailURL": "https://images.unsplash.com/photo-1631452180519-c014fe946bc7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
    "spiceLevel": 0,
    "status": "Ready",
    "tagLine": "Spicy touch for your taste buds!!",
    "updateDateTime": "2022-04-28T17:21:02.657636"
}

8. 축하합니다.

축하합니다. Codelab을 완료했습니다.

다음 단계:

다른 Cymbal Eats Codelab 살펴보기:

삭제

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

프로젝트 삭제

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.