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. SQL 서버용 Cloud SQL 인스턴스를 만듭니다. 지연 시간을 개선하고, 일부 네트워킹 비용을 방지하고, 리전 간 장애 위험을 줄이려면 Cloud Run 서비스와 동일한 리전에 있는 Cloud SQL 인스턴스 위치를 선택하는 것이 좋습니다.

    기본적으로 Cloud SQL은 공개 IP 주소를 새 인스턴스에 할당합니다. 비공개 IP 주소를 할당할 수도 있습니다. 두 옵션의 연결 옵션에 대한 자세한 내용은 연결 개요 페이지를 참조하세요.

Cloud Run 구성

Cloud Run을 구성하는 단계는 Cloud SQL 인스턴스에 할당된 IP 주소 유형에 따라 다릅니다. 직접 VPC 이그레스 또는 서버리스 VPC 액세스 커넥터를 통해 모든 이그레스 트래픽을 라우팅하는 경우 비공개 IP 주소를 사용합니다. 두 가지 네트워크 이그레스 방법을 비교합니다.

공개 IP(기본값)

Cloud Run은 Go, Java, Python 커넥터를 사용해서 공개 IP를 통한 SQL Server용 Cloud SQL에 연결을 지원합니다.

  • 앞에서 만든 인스턴스에 공개 IP 주소가 있는지 확인합니다. Google Cloud 콘솔의 인스턴스에 대한 개요 페이지에서 이를 확인할 수 있습니다. 공개 IP 주소를 추가해야 하는 경우 공개 IP 구성 페이지의 안내를 참조하세요.
  • 인스턴스의 INSTANCE_CONNECTION_NAME을 가져옵니다. Google Cloud 콘솔의 인스턴스에 대한 개요 페이지에서 확인하거나 gcloud sql instances describe INSTANCE_NAME 명령어를 실행하여 확인할 수 있습니다.
  • Cloud Run 서비스의 서비스 계정을 구성합니다. 서비스 계정에 Cloud SQL에 연결하기 위한 적절한 Cloud SQL 역할과 권한이 있는지 확인합니다.
    • 서비스의 서비스 계정에는 다음 IAM 역할 중 하나가 필요합니다.
      • Cloud SQL Client(권장)
      • Cloud SQL Admin
      또는 다음 IAM 권한을 수동으로 할당할 수 있습니다.
      • cloudsql.instances.connect
      • cloudsql.instances.get

다른 구성 변경과 마찬가지로 Cloud SQL 연결의 새 구성을 설정하면 새 Cloud Run 버전이 생성됩니다. 이를 변경하는 명시적 업데이트가 없으면 이후 버전에서도 이 Cloud SQL 연결이 자동으로 적용됩니다.

콘솔

  1. Cloud Run으로 이동

  2. 서비스 구성을 시작합니다.

    • 새 서비스에 Cloud SQL 연결을 추가하는 경우:

      서비스를 컨테이너화하여 Container Registry 또는 Artifact Registry에 업로드해야 합니다. 아직 컨테이너 이미지가 없으면 컨테이너 이미지 빌드 및 배포에 대한 안내를 참조하세요.

    • 기존 서비스에 Cloud SQL 연결을 추가하는 경우:
      1. 서비스 이름을 클릭합니다.
      2. 새 버전 수정 및 배포 탭을 클릭합니다.
  3. Cloud SQL 인스턴스에 연결 사용 설정:
    1. 컨테이너, 변수 및 보안 비밀, 연결, 보안을 클릭합니다.
    2. 컨테이너 탭을 클릭합니다.
    3. Cloud SQL 연결까지 아래로 스크롤합니다.
    4. 연결 추가를 클릭합니다.
    5. 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 VPNVPC 네트워크 피어링을 사용하여 연결된 VPC 네트워크와의 통신을 지원합니다.
    • 직접 VPC 이그레스와 서버리스 VPC 액세스는 기존 네트워크를 지원하지 않습니다.
    • 공유 VPC를 사용하지 않는 한 커넥터는 커넥터를 사용하는 리소스와 동일한 프로젝트와 리전에 있어야 하지만 이 커넥터는 서로 다른 리전의 리소스로 트래픽을 전송할 수 있습니다.
  3. 인스턴스의 비공개 IP 주소와 포트 1433를 사용하여 연결합니다.

Cloud SQL에 연결

Cloud Run을 구성한 후 Cloud SQL 인스턴스에 연결할 수 있습니다.

공개 IP(기본값)

공개 IP 경로의 경우 Cloud Run은 암호화를 제공하고 Cloud SQL 커넥터를 사용하여 연결합니다.

Cloud SQL 커넥터와 연결

Cloud SQL 커넥터는 Cloud SQL 인스턴스에 연결할 때 암호화 및 IAM 기반 승인을 제공하는 언어별 라이브러리입니다.

Python

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

import os

from google.cloud.sql.connector import Connector, IPTypes
import pytds

import sqlalchemy


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
    """
    Initializes a connection pool for a Cloud SQL instance of SQL Server.

    Uses the Cloud SQL Python Connector package.
    """
    # 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.

    instance_connection_name = os.environ[
        "INSTANCE_CONNECTION_NAME"
    ]  # e.g. 'project:region:instance'
    db_user = os.environ.get("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'

    ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

    connector = Connector(ip_type)

    connect_args = {}
    # If your SQL Server instance requires SSL, you need to download the CA
    # certificate for your instance and include cafile={path to downloaded
    # certificate} and validate_host=False. This is a workaround for a known issue.
    if os.environ.get("DB_ROOT_CERT"):  # e.g. '/path/to/my/server-ca.pem'
        connect_args = {
            "cafile": os.environ["DB_ROOT_CERT"],
            "validate_host": False,
        }

    def getconn() -> pytds.Connection:
        conn = connector.connect(
            instance_connection_name,
            "pytds",
            user=db_user,
            password=db_pass,
            db=db_name,
            **connect_args
        )
        return conn

    pool = sqlalchemy.create_engine(
        "mssql+pytds://",
        creator=getconn,
        # ...
    )
    return pool

자바

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

참고:

  • CLOUD_SQL_CONNECTION_NAME은 <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>으로 표현되어야 합니다.
  • pom.xml 파일에 대한 JDBC 소켓 팩토리 버전 요구사항은 여기를 참조하세요.


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

public class ConnectorConnectionPoolFactory 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 INSTANCE_CONNECTION_NAME =
      System.getenv("INSTANCE_CONNECTION_NAME");
  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");

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

    // The following is equivalent to setting the config options below:
    // jdbc:sqlserver://;user=<DB_USER>;password=<DB_PASS>;databaseName=<DB_NAME>;
    // socketFactoryClass=com.google.cloud.sql.sqlserver.SocketFactory;
    // socketFactoryConstructorArg=<INSTANCE_CONNECTION_NAME>

    // 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
        .setDataSourceClassName("com.microsoft.sqlserver.jdbc.SQLServerDataSource");
    config.setUsername(DB_USER); // e.g. "root", "sqlserver"
    config.setPassword(DB_PASS); // e.g. "my-password"
    config.addDataSourceProperty("databaseName", DB_NAME);

    config.addDataSourceProperty("socketFactoryClass",
        "com.google.cloud.sql.sqlserver.SocketFactory");
    config.addDataSourceProperty("socketFactoryConstructorArg", INSTANCE_CONNECTION_NAME);

    // The Java Connector provides SSL encryption, so it should be disabled
    // at the driver level.
    config.addDataSourceProperty("encrypt", "false");

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

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

Go

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

package cloudsql

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

	"cloud.google.com/go/cloudsqlconn"
	mssql "github.com/denisenkom/go-mssqldb"
)

type csqlDialer struct {
	dialer     *cloudsqlconn.Dialer
	connName   string
	usePrivate bool
}

// DialContext adheres to the mssql.Dialer interface.
func (c *csqlDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
	var opts []cloudsqlconn.DialOption
	if c.usePrivate {
		opts = append(opts, cloudsqlconn.WithPrivateIP())
	}
	return c.dialer.Dial(ctx, c.connName, opts...)
}

func connectWithConnector() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Fatal Error in connect_connector.go: %s environment variable not set.\n", 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'
		dbName                 = mustGetenv("DB_NAME")                  // e.g. 'my-database'
		instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME") // e.g. 'project:region:instance'
		usePrivate             = os.Getenv("PRIVATE_IP")
	)

	dbURI := fmt.Sprintf("user id=%s;password=%s;database=%s;", dbUser, dbPwd, dbName)
	c, err := mssql.NewConnector(dbURI)
	if err != nil {
		return nil, fmt.Errorf("mssql.NewConnector: %w", err)
	}
	dialer, err := cloudsqlconn.NewDialer(context.Background())
	if err != nil {
		return nil, fmt.Errorf("cloudsqlconn.NewDailer: %w", err)
	}
	c.Dialer = &csqlDialer{
		dialer:     dialer,
		connName:   instanceConnectionName,
		usePrivate: usePrivate != "",
	}

	dbPool := sql.OpenDB(c)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}
	return dbPool, nil
}

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_secretgoogle_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 주소를 호스트 및 포트 1433로 사용하여 연결합니다.

Python

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

import os

import sqlalchemy


def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
    """Initializes a TCP connection pool for a Cloud SQL instance of SQL Server."""
    # 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. 1433

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

    return pool

자바

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

참고:

  • CLOUD_SQL_CONNECTION_NAME은 <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>으로 표현되어야 합니다.
  • 인수 ipTypes=PRIVATE을 사용하면 SocketFactory가 인스턴스의 연결된 비공개 IP와 강제로 연결됩니다.
  • pom.xml 파일에 대한 JDBC 소켓 팩토리 버전 요구사항은 여기를 참조하세요.


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();

    // Configure which instance and what database user to connect with.
    config.setJdbcUrl(
        String.format("jdbc:sqlserver://%s:%s;databaseName=%s", INSTANCE_HOST, DB_PORT, DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", "sqlserver"
    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 mssql = require('mssql');

// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of SQL Server.
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 = {
    server: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
    port: parseInt(process.env.DB_PORT), // e.g. 1433
    user: process.env.DB_USER, // e.g. 'my-db-user'
    password: process.env.DB_PASS, // e.g. 'my-db-password'
    database: process.env.DB_NAME, // e.g. 'my-database'
    options: {
      trustServerCertificate: true,
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return mssql.connect(dbConfig);
};

Go

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

package cloudsql

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

	_ "github.com/denisenkom/go-mssqldb"
)

// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of SQL Server.
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.\n", 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. '1433'
		dbName    = mustGetenv("DB_NAME")       // e.g. 'my-database'
	)

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


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

	// ...

	return dbPool, nil
}

Ruby

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

tcp: &tcp
  adapter: sqlserver
  # 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") { 1433 }%> 

PHP

웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.

namespace Google\Cloud\Samples\CloudSQL\SQLServer;

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(
                'sqlsrv:server=%s;Database=%s',
                $instanceHost,
                $dbName
            );

            // 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/sqlserver/connect-external-app',
                    $e->getMessage()
                ),
                (int) $e->getCode(),
                $e
            );
        }

        return $conn;
    }
}

권장사항 및 기타 정보

로컬에서 애플리케이션을 테스트할 때 Cloud SQL 인증 프록시를 사용할 수 있습니다. 자세한 내용은 빠른 시작: Cloud SQL 인증 프록시 사용을 참조하세요.

Docker 컨테이너를 통해 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 할당량을 수정할 수 있습니다.

다음 단계