Cloud Run์—์„œ ์—ฐ๊ฒฐ

์ด ํŽ˜์ด์ง€์—๋Š” Cloud Run์—์„œ ์‹คํ–‰๋˜๋Š” ์„œ๋น„์Šค์—์„œ Cloud SQL ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ •๋ณด์™€ ์˜ˆ์‹œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Cloud SQL์— ์—ฐ๊ฒฐ๋œ Cloud Run ์ƒ˜ํ”Œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋‹จ๊ณ„๋ณ„ ์•ˆ๋‚ด๋Š” ๋น ๋ฅธ ์‹œ์ž‘: Cloud Run์—์„œ ์—ฐ๊ฒฐ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Cloud SQL์€ ํด๋ผ์šฐ๋“œ์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ค์ •, ์œ ์ง€, ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์™„์ „ ๊ด€๋ฆฌํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

Cloud Run์€ Google Cloud ์ธํ”„๋ผ์—์„œ ์ง์ ‘ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ด€๋ฆฌํ˜• ์ปดํ“จํŒ… ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.

Cloud SQL ์ธ์Šคํ„ด์Šค ์„ค์ •

  1. ์•„์ง ์‚ฌ์šฉ ์„ค์ •ํ•˜์ง€ ์•Š์•˜์œผ๋ฉด ์—ฐ๊ฒฐ ์ค‘์ธ Google Cloud ํ”„๋กœ์ ํŠธ์—์„œ Cloud SQL Admin API๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

    Enable the API

  2. PostgreSQL์šฉ Cloud SQL ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ์„ธ์š”. ์ง€์—ฐ ์‹œ๊ฐ„์„ ๊ฐœ์„ ํ•˜๊ณ , ์ผ๋ถ€ ๋„คํŠธ์›Œํ‚น ๋น„์šฉ ๋ฐœ์ƒ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ๋ฆฌ์ „ ๊ฐ„ ์žฅ์•  ์œ„ํ—˜์„ ์ค„์ด๋ ค๋ฉด Cloud Run ์„œ๋น„์Šค์™€ ๋™์ผํ•œ ๋ฆฌ์ „์— ์žˆ๋Š” Cloud SQL ์ธ์Šคํ„ด์Šค ์œ„์น˜๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    ๊ธฐ๋ณธ์ ์œผ๋กœ Cloud SQL์€ ๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ์ƒˆ ์ธ์Šคํ„ด์Šค์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ํ• ๋‹นํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ์˜ต์…˜์˜ ์—ฐ๊ฒฐ ์˜ต์…˜์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฐ๊ฒฐ ๊ฐœ์š” ํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

  3. ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ ์ธ์Šคํ„ด์Šค์˜ ์„œ๋ฒ„ ์ธ์ฆ์„œ(CA) ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์„ ํƒํ•œ ๋‹ค์Œ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์ธ์Šคํ„ด์Šค์˜ serverCaMode๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์—ฐ๊ฒฐํ•  ์ธ์Šคํ„ด์Šค์˜ ์„œ๋ฒ„ CA ๋ชจ๋“œ๋กœ ์ธ์Šคํ„ด์Šค๋ณ„ CA ์˜ต์…˜(GOOGLE_MANAGED_INTERNAL_CA)์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Cloud Run ๊ตฌ์„ฑ

Cloud Run์„ ๊ตฌ์„ฑํ•˜๋Š” ๋‹จ๊ณ„๋Š” Cloud SQL ์ธ์Šคํ„ด์Šค์— ํ• ๋‹น๋œ IP ์ฃผ์†Œ ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ด๊ทธ๋ ˆ์Šค ํŠธ๋ž˜ํ”ฝ์„ ์ง์ ‘ VPC ์ด๊ทธ๋ ˆ์Šค๋‚˜ ์„œ๋ฒ„๋ฆฌ์Šค VPC ์•ก์„ธ์Šค ์ปค๋„ฅํ„ฐ๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ…ํ•˜๋Š” ๊ฒฝ์šฐ ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๋„คํŠธ์›Œํฌ ์ด๊ทธ๋ ˆ์Šค ๋ฐฉ๋ฒ•์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

๊ณต๊ฐœ IP(๊ธฐ๋ณธ๊ฐ’)

  • ์ธ์Šคํ„ด์Šค์— ๊ณต๊ฐœ IP ์ฃผ์†Œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. Google Cloud ์ฝ˜์†”์˜ ์ธ์Šคํ„ด์Šค ๊ฐœ์š” ํŽ˜์ด์ง€์—์„œ ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๊ณต๊ฐœ IP ๊ตฌ์„ฑ ํŽ˜์ด์ง€์˜ ์•ˆ๋‚ด๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
  • ์ธ์Šคํ„ด์Šค์˜ INSTANCE_CONNECTION_NAME์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. Google Cloud ์ฝ˜์†”์˜ ์ธ์Šคํ„ด์Šค ๊ฐœ์š” ํŽ˜์ด์ง€์—์„œ ๋˜๋Š” ๋‹ค์Œ gcloud sql instances describe ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ด ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    gcloud sql instances describe INSTANCE_NAME
       
    INSTANCE_NAME์„ Cloud SQL ์ธ์Šคํ„ด์Šค ์ด๋ฆ„์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • Cloud Run ์„œ๋น„์Šค์˜ CLOUD_RUN_SERVICE_ACCOUNT_NAME์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. Google Cloud ์ฝ˜์†”์—์„œ Cloud Run ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ํ”„๋กœ์ ํŠธ์˜ IAM ํŽ˜์ด์ง€์—์„œ ๋˜๋Š” Cloud Run ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ๋‹ค์Œ gcloud run services describe ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ด ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    gcloud run services describe CLOUD_RUN_SERVICE_NAME
    --region CLOUD_RUN_SERVICE_REGION --format="value(spec.template.spec.serviceAccountName)"
       
    ๋‹ค์Œ ๋ณ€์ˆ˜๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
    • CLOUD_RUN_SERVICE_NAME: Cloud Run ์„œ๋น„์Šค ์ด๋ฆ„
    • CLOUD_RUN_SERVICE_REGION: Cloud Run ์„œ๋น„์Šค ๋ฆฌ์ „
  • Cloud Run ์„œ๋น„์Šค์˜ ์„œ๋น„์Šค ๊ณ„์ •์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. Cloud SQL์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ์„œ๋น„์Šค ๊ณ„์ •์— Cloud SQL Client IAM ์—ญํ• ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • Cloud SQL ์—ฐ๊ฒฐ์„ ์ƒˆ ์„œ๋น„์Šค์— ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์„œ๋น„์Šค๋ฅผ ์ปจํ…Œ์ด๋„ˆํ™”ํ•˜์—ฌ Container Registry ๋˜๋Š” Artifact Registry์— ์—…๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ์— ๋Œ€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.
  • ์„œ๋ฒ„ CA ๋ชจ๋“œ๊ฐ€ ๊ณต์œ  ์ธ์ฆ ๊ธฐ๊ด€(CA)(GOOGLE_MANAGED_CAS_CA) ์˜ต์…˜ ๋˜๋Š” ๊ณ ๊ฐ ๊ด€๋ฆฌ CA(CUSTOMER_MANAGED_CAS_CA) ์˜ต์…˜์œผ๋กœ ๊ตฌ์„ฑ๋œ ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ ์„œ๋น„์Šค์˜ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์„ ํƒํ•  ๋•Œ 2์„ธ๋Œ€ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๋‘ ์„œ๋ฒ„ CA ๋ชจ๋“œ ์˜ต์…˜ ๋ชจ๋‘ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ v2๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์„œ๋น„์Šค๊ฐ€ 1์„ธ๋Œ€ ์‹คํ–‰ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ ์„œ๋ฒ„ CA ๋ชจ๋“œ๊ฐ€ ์ธ์Šคํ„ด์Šค๋ณ„ ์ธ์ฆ ๊ธฐ๊ด€(CA) ์˜ต์…˜(GOOGLE_MANAGED_INTERNAL_CA)์œผ๋กœ ๊ตฌ์„ฑ๋œ Cloud SQL ์ธ์Šคํ„ด์Šค์—๋งŒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Cloud Run 1์„ธ๋Œ€ ์‹คํ–‰ ํ™˜๊ฒฝ์€ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ v1์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค. Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ์˜ Cloud SQL ์—ฐ๊ฒฐ ์š”๊ตฌ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ ์‚ฌ์šฉ ์‹œ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋‹ค๋ฅธ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Cloud SQL ์—ฐ๊ฒฐ์˜ ์ƒˆ ๊ตฌ์„ฑ์„ ์„ค์ •ํ•˜๋ฉด ์ƒˆ Cloud Run ๋ฒ„์ „์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ช…์‹œ์  ์—…๋ฐ์ดํŠธ๊ฐ€ ์—†์œผ๋ฉด ์ดํ›„ ๋ฒ„์ „์—์„œ๋„ ์ด Cloud SQL ์—ฐ๊ฒฐ์ด ์ž๋™์œผ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ฝ˜์†”

  1. Cloud Run์œผ๋กœ ์ด๋™

  2. ์„œ๋น„์Šค ๊ตฌ์„ฑ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. Cloud SQL ์—ฐ๊ฒฐ์„ ๊ธฐ์กด ์„œ๋น„์Šค์— ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    1. ์„œ๋น„์Šค ๋ชฉ๋ก์—์„œ ์›ํ•˜๋Š” ์„œ๋น„์Šค ์ด๋ฆ„์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    2. ์ƒˆ ๋ฒ„์ „ ์ˆ˜์ • ๋ฐ ๋ฐฐํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. Cloud SQL ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐ ์‚ฌ์šฉ ์„ค์ •:
    1. ์ปจํ…Œ์ด๋„ˆ์™€ ์„ค์ •์„ ์ฐจ๋ก€๋Œ€๋กœ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    2. Cloud SQL ์—ฐ๊ฒฐ๋กœ ์Šคํฌ๋กคํ•ฉ๋‹ˆ๋‹ค.
    3. ์—ฐ๊ฒฐ ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    4. Cloud SQL Admin API๋ฅผ ์•„์ง ์‚ฌ์šฉ ์„ค์ •ํ•˜์ง€ ์•Š์•˜์œผ๋ฉด Cloud SQL Admin ์‚ฌ์šฉ ์„ค์ • ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

    Cloud SQL ์—ฐ๊ฒฐ ์ถ”๊ฐ€

    • ์—ฐ๊ฒฐ์„ ํ”„๋กœ์ ํŠธ์˜ Cloud SQL ์ธ์Šคํ„ด์Šค์— ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋ฉ”๋‰ด์—์„œ ์›ํ•˜๋Š” Cloud SQL ์ธ์Šคํ„ด์Šค๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
    • ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์˜ Cloud SQL ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฉ”๋‰ด์—์„œ ์ปค์Šคํ…€ ์—ฐ๊ฒฐ ๋ฌธ์ž์—ด์„ ์„ ํƒํ•˜๊ณ  ์ „์ฒด ์ธ์Šคํ„ด์Šค ์—ฐ๊ฒฐ ์ด๋ฆ„์„ PROJECT-ID:REGION:INSTANCE-ID ํ˜•์‹์œผ๋กœ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
    • ์—ฐ๊ฒฐ์„ ์‚ญ์ œํ•˜๋ ค๋ฉด ์ปค์„œ๋ฅผ ์—ฐ๊ฒฐ ์˜ค๋ฅธ์ชฝ์— ๊ฐ€์ ธ๊ฐ€์„œ ์‚ญ์ œ ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•˜๊ณ  ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  4. ๋งŒ๋“ค๊ธฐ ๋˜๋Š” ๋ฐฐํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

๋ช…๋ น์ค„

๋‹ค์Œ ๋ช…๋ น์–ด ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

  • IMAGE๋ฅผ ๋ฐฐํฌํ•  ์ด๋ฏธ์ง€๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • SERVICE_NAME: Cloud Run ์„œ๋น„์Šค ์ด๋ฆ„
  • INSTANCE_CONNECTION_NAME์„ Cloud SQL ์ธ์Šคํ„ด์Šค์˜ ์ธ์Šคํ„ด์Šค ์—ฐ๊ฒฐ ์ด๋ฆ„ ๋˜๋Š” ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์—ฐ๊ฒฐ ์ด๋ฆ„ ๋ชฉ๋ก์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

    ์ƒˆ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ฐฐํฌํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    gcloud run deploy \
      --image=IMAGE \
      --add-cloudsql-instances=INSTANCE_CONNECTION_NAME
    ๊ธฐ์กด ์„œ๋น„์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    gcloud run services update SERVICE_NAME \
      --add-cloudsql-instances=INSTANCE_CONNECTION_NAME

Terraform

๋‹ค์Œ ์ฝ”๋“œ๋Š” ์—ฐ๊ฒฐ๋œ Cloud SQL ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ Cloud Run ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

resource "google_cloud_run_v2_service" "default" {
  name     = "cloudrun-service"
  location = "us-central1"

  deletion_protection = false # set to "true" in production

  template {
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello:latest" # Image to deploy

      volume_mounts {
        name       = "cloudsql"
        mount_path = "/cloudsql"
      }
    }
    volumes {
      name = "cloudsql"
      cloud_sql_instance {
        instances = [google_sql_database_instance.default.connection_name]
      }
    }
  }
  client     = "terraform"
  depends_on = [google_project_service.secretmanager_api, google_project_service.cloudrun_api, google_project_service.sqladmin_api]
}

  1. terraform apply๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  2. Cloud Run ์„œ๋น„์Šค๋ฅผ ์„ ํƒํ•˜๊ณ  ๋ฒ„์ „ ํƒญ, ์—ฐ๊ฒฐ ํƒญ์„ ์ฐจ๋ก€๋กœ ํด๋ฆญํ•˜์—ฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋น„๊ณต๊ฐœ IP

์Šน์ธ ์„œ๋น„์Šค ๊ณ„์ •์ด Cloud SQL ์ธ์Šคํ„ด์Šค๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์— ์†ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ๋‘ ํ”„๋กœ์ ํŠธ ๋ชจ๋‘์—์„œ Cloud SQL Admin API๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Cloud SQL ์ธ์Šคํ„ด์Šค๊ฐ€ ํฌํ•จ๋œ ํ”„๋กœ์ ํŠธ์˜ ์„œ๋น„์Šค ๊ณ„์ •์— IAM ๊ถŒํ•œ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
์ง์ ‘ VPC ์ด๊ทธ๋ ˆ์Šค ๋ฐ ์ปค๋„ฅํ„ฐ๋Š” ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ VPC ๋„คํŠธ์›Œํฌ์™€์˜ ํ†ต์‹ ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด๊ทธ๋ ˆ์Šค ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ์™€ ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  1. ์œ„์—์„œ ๋งŒ๋“  Cloud SQL ์ธ์Šคํ„ด์Šค์— ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ IP ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋น„๊ณต๊ฐœ IP ๊ตฌ์„ฑ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.
  2. ์ด๊ทธ๋ ˆ์Šค ๋ฐฉ๋ฒ•์„ ๊ตฌ์„ฑํ•˜์—ฌ Cloud SQL ์ธ์Šคํ„ด์Šค์™€ ๋™์ผํ•œ VPC ๋„คํŠธ์›Œํฌ์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์กฐ๊ฑด์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.
    • ์ง์ ‘ VPC ์ด๊ทธ๋ ˆ์Šค์™€ ์„œ๋ฒ„๋ฆฌ์Šค VPC ์•ก์„ธ์Šค ๋ชจ๋‘ Cloud VPN ๋ฐ VPC ๋„คํŠธ์›Œํฌ ํ”ผ์–ด๋ง์„ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ VPC ๋„คํŠธ์›Œํฌ์™€์˜ ํ†ต์‹ ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
    • ์ง์ ‘ VPC ์ด๊ทธ๋ ˆ์Šค์™€ ์„œ๋ฒ„๋ฆฌ์Šค VPC ์•ก์„ธ์Šค๋Š” ๊ธฐ์กด ๋„คํŠธ์›Œํฌ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ๊ณต์œ  VPC๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ ์ปค๋„ฅํ„ฐ๋Š” ์ปค๋„ฅํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฆฌ์†Œ์Šค์™€ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ์™€ ๋ฆฌ์ „์— ์žˆ์–ด์•ผ ํ•˜์ง€๋งŒ ์ด ์ปค๋„ฅํ„ฐ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋ฆฌ์ „์˜ ๋ฆฌ์†Œ์Šค๋กœ ํŠธ๋ž˜ํ”ฝ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ธ์Šคํ„ด์Šค์˜ ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ์™€ ํฌํŠธ 5432๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

Cloud SQL์— ์—ฐ๊ฒฐ

Cloud Run์„ ๊ตฌ์„ฑํ•œ ํ›„ Cloud SQL ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต๊ฐœ IP(๊ธฐ๋ณธ๊ฐ’)

๊ณต๊ฐœ IP ๊ฒฝ๋กœ์˜ ๊ฒฝ์šฐ Cloud Run์€ ์•”ํ˜ธํ™”๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

Secret Manager ์‚ฌ์šฉ

Secret Manager๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SQL ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Cloud Run์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด์•ˆ ๋น„๋ฐ€์„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ๋ณผ๋ฅจ์œผ๋กœ ๋งˆ์šดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Secret Manager์—์„œ ๋ณด์•ˆ ๋น„๋ฐ€์„ ๋งŒ๋“  ํ›„ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ์„œ๋น„์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

๋ช…๋ น์ค„

gcloud run services update SERVICE_NAME \
  --add-cloudsql-instances=INSTANCE_CONNECTION_NAME
  --update-env-vars=INSTANCE_CONNECTION_NAME=INSTANCE_CONNECTION_NAME_SECRET \
  --update-secrets=DB_USER=DB_USER_SECRET:latest \
  --update-secrets=DB_PASS=DB_PASS_SECRET:latest \
  --update-secrets=DB_NAME=DB_NAME_SECRET:latest

Terraform

๋‹ค์Œ์€ google_secret_manager_secret ๋ฐ google_secret_manager_secret_version์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉ์ž, ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ด๋ฆ„ ๊ฐ’์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•˜๋Š” ๋ณด์•ˆ ๋น„๋ฐ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฐ ๋ณด์•ˆ ๋น„๋ฐ€์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ํ”„๋กœ์ ํŠธ ์ปดํ“จํŒ… ์„œ๋น„์Šค ๊ณ„์ •์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


# Create dbuser secret
resource "google_secret_manager_secret" "dbuser" {
  secret_id = "dbusersecret"
  replication {
    auto {}
  }
  depends_on = [google_project_service.secretmanager_api]
}

# Attaches secret data for dbuser secret
resource "google_secret_manager_secret_version" "dbuser_data" {
  secret      = google_secret_manager_secret.dbuser.id
  secret_data = "secret-data" # Stores secret as a plain txt in state
}

# Update service account for dbuser secret
resource "google_secret_manager_secret_iam_member" "secretaccess_compute_dbuser" {
  secret_id = google_secret_manager_secret.dbuser.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com" # Project's compute service account
}


# Create dbpass secret
resource "google_secret_manager_secret" "dbpass" {
  secret_id = "dbpasssecret"
  replication {
    auto {}
  }
  depends_on = [google_project_service.secretmanager_api]
}

# Attaches secret data for dbpass secret
resource "google_secret_manager_secret_version" "dbpass_data" {
  secret      = google_secret_manager_secret.dbpass.id
  secret_data = "secret-data" # Stores secret as a plain txt in state
}

# Update service account for dbpass secret
resource "google_secret_manager_secret_iam_member" "secretaccess_compute_dbpass" {
  secret_id = google_secret_manager_secret.dbpass.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com" # Project's compute service account
}


# Create dbname secret
resource "google_secret_manager_secret" "dbname" {
  secret_id = "dbnamesecret"
  replication {
    auto {}
  }
  depends_on = [google_project_service.secretmanager_api]
}

# Attaches secret data for dbname secret
resource "google_secret_manager_secret_version" "dbname_data" {
  secret      = google_secret_manager_secret.dbname.id
  secret_data = "secret-data" # Stores secret as a plain txt in state
}

# Update service account for dbname secret
resource "google_secret_manager_secret_iam_member" "secretaccess_compute_dbname" {
  secret_id = google_secret_manager_secret.dbname.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com" # Project's compute service account
}

์ƒˆ ๋ณด์•ˆ ๋น„๋ฐ€์„ ํฌํ•จํ•˜๋„๋ก ๊ธฐ๋ณธ Cloud Run ๋ฆฌ์†Œ์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

resource "google_cloud_run_v2_service" "default" {
  name     = "cloudrun-service"
  location = "us-central1"

  deletion_protection = false # set to "true" in production

  template {
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello:latest" # Image to deploy

      # Sets a environment variable for instance connection name
      env {
        name  = "INSTANCE_CONNECTION_NAME"
        value = google_sql_database_instance.default.connection_name
      }
      # Sets a secret environment variable for database user secret
      env {
        name = "DB_USER"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.dbuser.secret_id # secret name
            version = "latest"                                      # secret version number or 'latest'
          }
        }
      }
      # Sets a secret environment variable for database password secret
      env {
        name = "DB_PASS"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.dbpass.secret_id # secret name
            version = "latest"                                      # secret version number or 'latest'
          }
        }
      }
      # Sets a secret environment variable for database name secret
      env {
        name = "DB_NAME"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.dbname.secret_id # secret name
            version = "latest"                                      # secret version number or 'latest'
          }
        }
      }

      volume_mounts {
        name       = "cloudsql"
        mount_path = "/cloudsql"
      }
    }
    volumes {
      name = "cloudsql"
      cloud_sql_instance {
        instances = [google_sql_database_instance.default.connection_name]
      }
    }
  }
  client     = "terraform"
  depends_on = [google_project_service.secretmanager_api, google_project_service.cloudrun_api, google_project_service.sqladmin_api]
}

terraform apply๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์‹œ ๋ช…๋ น์–ด๋Š” ๋ณด์•ˆ ๋น„๋ฐ€ ๋ฒ„์ „ latest๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณด์•ˆ ๋น„๋ฐ€์„ ํŠน์ • ๋ฒ„์ „์ธ SECRET_NAME:v1์— ๊ณ ์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋น„๊ณต๊ฐœ IP

๋น„๊ณต๊ฐœ IP ๊ฒฝ๋กœ์˜ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ VPC ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ธ์Šคํ„ด์Šค์— ์ง์ ‘ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” TCP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  Cloud SQL ์ธ์Šคํ„ด์Šค์— ์ง์ ‘ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

TCP๋กœ ์—ฐ๊ฒฐ

Cloud SQL ์ธ์Šคํ„ด์Šค์˜ ๋น„๊ณต๊ฐœ IP ์ฃผ์†Œ๋ฅผ ํ˜ธ์ŠคํŠธ ๋ฐ ํฌํŠธ 5432๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

Python

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

import os
import ssl

import sqlalchemy


def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
    """Initializes a TCP connection pool for a Cloud SQL instance of Postgres."""
    # Note: Saving credentials in environment variables is convenient, but not
    # secure - consider a more secure solution such as
    # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
    # keep secrets safe.
    db_host = os.environ[
        "INSTANCE_HOST"
    ]  # e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
    db_user = os.environ["DB_USER"]  # e.g. 'my-db-user'
    db_pass = os.environ["DB_PASS"]  # e.g. 'my-db-password'
    db_name = os.environ["DB_NAME"]  # e.g. 'my-database'
    db_port = os.environ["DB_PORT"]  # e.g. 5432

    pool = sqlalchemy.create_engine(
        # Equivalent URL:
        # postgresql+pg8000://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
        sqlalchemy.engine.url.URL.create(
            drivername="postgresql+pg8000",
            username=db_user,
            password=db_pass,
            host=db_host,
            port=db_port,
            database=db_name,
        ),
        # ...
    )
    return pool

Java

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ฐธ๊ณ :


import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;

public class TcpConnectionPoolFactory extends ConnectionPoolFactory {

  // Note: Saving credentials in environment variables is convenient, but not
  // secure - consider a more secure solution such as
  // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  // keep secrets safe.
  private static final String DB_USER = System.getenv("DB_USER");
  private static final String DB_PASS = System.getenv("DB_PASS");
  private static final String DB_NAME = System.getenv("DB_NAME");

  private static final String INSTANCE_HOST = System.getenv("INSTANCE_HOST");
  private static final String DB_PORT = System.getenv("DB_PORT");


  public static DataSource createConnectionPool() {
    // The configuration object specifies behaviors for the connection pool.
    HikariConfig config = new HikariConfig();

    // The following URL is equivalent to setting the config options below:
    // jdbc:postgresql://<INSTANCE_HOST>:<DB_PORT>/<DB_NAME>?user=<DB_USER>&password=<DB_PASS>
    // See the link below for more info on building a JDBC URL for the Cloud SQL JDBC Socket Factory
    // https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory#creating-the-jdbc-url

    // Configure which instance and what database user to connect with.
    config.setJdbcUrl(String.format("jdbc:postgresql://%s:%s/%s", INSTANCE_HOST, DB_PORT, DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", "postgres"
    config.setPassword(DB_PASS); // e.g. "my-password"


    // ... Specify additional connection properties here.
    // ...

    // Initialize the connection pool using the configuration object.
    return new HikariDataSource(config);
  }
}

Node.js

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

const Knex = require('knex');
const fs = require('fs');

// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of Postgres.
const createTcpPool = async config => {
  // Note: Saving credentials in environment variables is convenient, but not
  // secure - consider a more secure solution such as
  // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  // keep secrets safe.
  const dbConfig = {
    client: 'pg',
    connection: {
      host: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
      port: process.env.DB_PORT, // e.g. '5432'
      user: process.env.DB_USER, // e.g. 'my-user'
      password: process.env.DB_PASS, // e.g. 'my-user-password'
      database: process.env.DB_NAME, // e.g. 'my-database'
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return Knex(dbConfig);
};

Go

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

package cloudsql

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	// Note: If connecting using the App Engine Flex Go runtime, use
	// "github.com/jackc/pgx/stdlib" instead, since v5 requires
	// Go modules which are not supported by App Engine Flex.
	_ "github.com/jackc/pgx/v5/stdlib"
)

// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of Postgres.
func connectTCPSocket() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Fatal Error in connect_tcp.go: %s environment variable not set.", k)
		}
		return v
	}
	// Note: Saving credentials in environment variables is convenient, but not
	// secure - consider a more secure solution such as
	// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
	// keep secrets safe.
	var (
		dbUser    = mustGetenv("DB_USER")       // e.g. 'my-db-user'
		dbPwd     = mustGetenv("DB_PASS")       // e.g. 'my-db-password'
		dbTCPHost = mustGetenv("INSTANCE_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
		dbPort    = mustGetenv("DB_PORT")       // e.g. '5432'
		dbName    = mustGetenv("DB_NAME")       // e.g. 'my-database'
	)

	dbURI := fmt.Sprintf("host=%s user=%s password=%s port=%s database=%s",
		dbTCPHost, dbUser, dbPwd, dbPort, dbName)


	// dbPool is the pool of database connections.
	dbPool, err := sql.Open("pgx", dbURI)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}

	// ...

	return dbPool, nil
}

C#

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

using Npgsql;
using System;

namespace CloudSql
{
    public class PostgreSqlTcp
    {
        public static NpgsqlConnectionStringBuilder NewPostgreSqlTCPConnectionString()
        {
            // Equivalent connection string:
            // "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<INSTANCE_HOST>;Database=<DB_NAME>;"
            var connectionString = new NpgsqlConnectionStringBuilder()
            {
                // Note: Saving credentials in environment variables is convenient, but not
                // secure - consider a more secure solution such as
                // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
                // keep secrets safe.
                Host = Environment.GetEnvironmentVariable("INSTANCE_HOST"),     // e.g. '127.0.0.1'
                // Set Host to 'cloudsql' when deploying to App Engine Flexible environment
                Username = Environment.GetEnvironmentVariable("DB_USER"), // e.g. 'my-db-user'
                Password = Environment.GetEnvironmentVariable("DB_PASS"), // e.g. 'my-db-password'
                Database = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'

                // The Cloud SQL proxy provides encryption between the proxy and instance.
                SslMode = SslMode.Disable,
            };
            connectionString.Pooling = true;
            // Specify additional properties here.
            return connectionString;
        }
    }
}

Ruby

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

tcp: &tcp
  adapter: postgresql
  # Configure additional properties here.
  # Note: Saving credentials in environment variables is convenient, but not
  # secure - consider a more secure solution such as
  # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  # keep secrets safe.
  username: <%= ENV["DB_USER"] %>  # e.g. "my-database-user"
  password: <%= ENV["DB_PASS"] %> # e.g. "my-database-password"
  database: <%= ENV.fetch("DB_NAME") { "vote_development" } %>
  host: <%= ENV.fetch("INSTANCE_HOST") { "127.0.0.1" }%> # '172.17.0.1' if deployed to GAE Flex
  port: <%= ENV.fetch("DB_PORT") { 5432 }%>

PHP

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ด ์Šค๋‹ˆํŽซ์„ ๋ณด๋ ค๋ฉด GitHub์˜ README๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

namespace Google\Cloud\Samples\CloudSQL\Postgres;

use PDO;
use PDOException;
use RuntimeException;
use TypeError;

class DatabaseTcp
{
    public static function initTcpDatabaseConnection(): PDO
    {
        try {
            // Note: Saving credentials in environment variables is convenient, but not
            // secure - consider a more secure solution such as
            // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
            // keep secrets safe.
            $username = getenv('DB_USER'); // e.g. 'your_db_user'
            $password = getenv('DB_PASS'); // e.g. 'your_db_password'
            $dbName = getenv('DB_NAME'); // e.g. 'your_db_name'
            $instanceHost = getenv('INSTANCE_HOST'); // e.g. '127.0.0.1' ('172.17.0.1' for GAE Flex)

            // Connect using TCP
            $dsn = sprintf('pgsql:dbname=%s;host=%s', $dbName, $instanceHost);

            // Connect to the database
            $conn = new PDO(
                $dsn,
                $username,
                $password,
                # ...
            );
        } catch (TypeError $e) {
            throw new RuntimeException(
                sprintf(
                    'Invalid or missing configuration! Make sure you have set ' .
                        '$username, $password, $dbName, and $instanceHost (for TCP mode). ' .
                        'The PHP error was %s',
                    $e->getMessage()
                ),
                $e->getCode(),
                $e
            );
        } catch (PDOException $e) {
            throw new RuntimeException(
                sprintf(
                    'Could not connect to the Cloud SQL Database. Check that ' .
                        'your username and password are correct, that the Cloud SQL ' .
                        'proxy is running, and that the database exists and is ready ' .
                        'for use. For more assistance, refer to %s. The PDO error was %s',
                    'https://cloud.google.com/sql/docs/postgres/connect-external-app',
                    $e->getMessage()
                ),
                $e->getCode(),
                $e
            );
        }

        return $conn;
    }
}

๊ถŒ์žฅ์‚ฌํ•ญ ๋ฐ ๊ธฐํƒ€ ์ •๋ณด

๋กœ์ปฌ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŠธํ•  ๋•Œ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋น ๋ฅธ ์‹œ์ž‘: Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ ์‚ฌ์šฉ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Docker ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด Cloud SQL ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ํ’€

๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋ฒ„ ์ž์ฒด ๋˜๋Š” ํ”Œ๋žซํผ ์ธํ”„๋ผ์— ์˜ํ•ด ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์ด ์ค‘๋‹จ๋˜์—ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์—ฐ๊ฒฐํ•˜๋Š” ์—ฐ๊ฒฐ ํ’€์„ ์ง€์›ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Cloud SQL ์ธ์Šคํ„ด์Šค์—์„œ ๊ด€๋ฆฌํ˜• ์—ฐ๊ฒฐ ํ’€๋ง์„ ์‚ฌ์šฉํ•˜๋ฉด ํ’€๋ง์„ ์‚ฌ์šฉํ•˜์—ฌ Cloud SQL ์ธ์Šคํ„ด์Šค์˜ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋ฅ ๊ณผ ์—ฐ๊ฒฐ ์ง€์—ฐ ์‹œ๊ฐ„์„ ์ตœ์ ํ™”ํ•˜์—ฌ ์›Œํฌ๋กœ๋“œ๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ฆฌํ˜• ์—ฐ๊ฒฐ ํ’€๋ง์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ด€๋ฆฌํ˜• ์—ฐ๊ฒฐ ํ’€๋ง ๊ฐœ์š”๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์—ฐ๊ฒฐ ํ’€ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์˜ˆ์‹œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๊ด€๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์—ฐ๊ฒฐ ํ•œ๋„

Cloud SQL์˜ MySQL๊ณผ PostgreSQL ๋ฒ„์ „ ๋ชจ๋‘ ๋™์‹œ ์—ฐ๊ฒฐ ์ˆ˜์— ์ตœ๋Œ€ ํ•œ๋„๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ•œ๋„๋Š” ์„ ํƒํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—”์ง„์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(Cloud SQL ํ• ๋‹น๋Ÿ‰ ๋ฐ ํ•œ๋„ ํŽ˜์ด์ง€ ์ฐธ์กฐ).

Cloud Run ์ปจํ…Œ์ด๋„ˆ ์ธ์Šคํ„ด์Šค๋Š” Cloud SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์ด 100๊ฐœ๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. Cloud Run ์„œ๋น„์Šค ๋˜๋Š” ์ž‘์—…์˜ ๊ฐ ์ธ์Šคํ„ด์Šค๋Š” 100๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ์„œ๋น„์Šค ๋˜๋Š” ์ž‘์—…์ด ํ™•์žฅ๋จ์— ๋”ฐ๋ผ ๋ฐฐํฌ๋‹น ์ด ์—ฐ๊ฒฐ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ํ’€์„ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋‹น ์‚ฌ์šฉ๋˜๋Š” ์ตœ๋Œ€ ์—ฐ๊ฒฐ ์ˆ˜๋ฅผ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์˜ˆ์‹œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๊ด€๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

API ํ• ๋‹น๋Ÿ‰ ํ•œ๋„

Cloud Run์€ Cloud SQL Admin API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. API ํ• ๋‹น๋Ÿ‰ ํ•œ๋„๊ฐ€ Cloud SQL ์ธ์ฆ ํ”„๋ก์‹œ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋œ Cloud SQL Admin API ํ• ๋‹น๋Ÿ‰์€ ํ•œ ๋ฒˆ์— ๋ฐฐํฌ๋œ ํŠน์ • ์„œ๋น„์Šค์˜ Cloud Run ์ธ์Šคํ„ด์Šค ์ˆ˜๋กœ ๊ตฌ์„ฑ๋œ Cloud SQL ์ธ์Šคํ„ด์Šค ์ˆ˜์˜ ์•ฝ 2๋ฐฐ์ž…๋‹ˆ๋‹ค. Cloud Run ์ธ์Šคํ„ด์Šค ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ฑฐ๋‚˜ ๋Š˜๋ ค ์‚ฌ์šฉ๋˜๋Š” ์˜ˆ์ƒ API ํ• ๋‹น๋Ÿ‰์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„