Google Kubernetes Engine에서 연결

이 페이지에서는 Google Kubernetes Engine에서 실행되는 애플리케이션에서 Cloud SQL 인스턴스로 연결을 설정하는 방법을 설명합니다.

소개

Google Kubernetes Engine에서 실행되는 애플리케이션에서 Cloud SQL 인스턴스에 액세스하려면 Cloud SQL 프록시(공개 또는 비공개 IP 사용)를 사용하거나 비공개 IP 주소를 사용하여 직접 연결할 수 있습니다.

비공개 IP를 사용하는 경우에도 Cloud SQL에 연결하는 데 Cloud SQL 프록시가 권장됩니다. 이는 프록시가 IAM을 사용하여 데이터베이스를 안전하게 보호할 수 있는 강력한 암호화와 인증을 제공하기 때문입니다.

데이터베이스 연결은 서버 및 연결 애플리케이션의 리소스를 사용합니다. 항상 연결 관리 권장사항을 참고하여 애플리케이션의 사용 공간을 최소화하고 Cloud SQL 연결 한도를 초과할 가능성을 줄이세요. 자세한 내용은 데이터베이스 연결 관리를 참조하세요.

시작하기 전에

Cloud SQL에 연결하려면 다음이 필요합니다.

  • kubectl 명령줄 도구가 설치되고 클러스터와 통신하도록 구성된 GKE 클러스터

    GKE를 시작하는 데 도움이 필요하면 빠른 시작을 참조하세요.

    비공개 IP를 사용하여 연결하려면 GKE 클러스터가 VPC 기반이여야 하며 Cloud SQL 인스턴스와 동일한 VPC 네트워크에 있어야 합니다.

  • 생성된 인스턴스

    Cloud SQL 인스턴스를 만들 때 도움이 필요하면 인스턴스 만들기를 참조하세요.

  • 인스턴스에 구성된 PostgreSQL 사용자 계정

    애플리케이션은 이 계정을 사용하여 데이터베이스에 연결합니다. 사용자 계정을 만드는 데 도움이 필요하면 사용자 만들기를 참조하세요.

보안 비밀 정보

Kubernetes에서 보안 비밀은 구성 세부정보를 애플리케이션에 전달하는 안전한 방법입니다. 데이터베이스 이름, 사용자, 비밀번호 등의 세부정보가 포함된 보안 비밀을 만들어 애플리케이션에 환경 변수로 삽입할 수 있습니다.

연결 유형에 따라 보안 비밀을 사용할 수 있는 여러 가지 방법이 있습니다.

  • 데이터베이스 사용자 인증 정보 보안 비밀에는 연결하려는 데이터베이스 사용자의 이름과 사용자의 데이터베이스 비밀번호가 포함됩니다.
  • 프록시로 연결하는 경우 보안 비밀을 사용하여 서비스 계정의 사용자 인증 정보 파일을 보관할 수 있습니다.
  • 비공개 IP로 연결하는 경우 보안 비밀을 사용하여 Cloud SQL 인스턴스의 비공개 IP 주소를 지정할 수 있습니다.

보안 비밀을 사용하는 방법에 대한 전체 예시는 이 페이지의 뒷부분에 설명된 GitHub 저장소를 참조하세요.

보안 비밀 객체 만들기

  1. 보안 비밀 객체를 만들려면 kubectl create secret 명령어를 사용합니다.

    데이터베이스 사용자 인증 정보 보안 비밀을 만들려면 다음과 같이 작성합니다.

    kubectl create secret generic <YOUR-DB-SECRET> \
      --from-literal=username=<YOUR-DATABASE-USER> \
      --from-literal=password=<YOUR-DATABASE-PASSWORD> \
      --from-literal=database=<YOUR-DATABASE-NAME>
    
  2. 객체가 생성되면 Cloud Console의 Google Kubernetes Engine 페이지에 있는 구성 섹션에서 확인할 수 있습니다.

Cloud SQL 프록시를 사용하여 연결

Cloud SQL 프록시를 사용하여 연결하면 Cloud SQL 프록시가 sidecar 컨테이너 패턴을 사용하여 pod에 추가됩니다. 프록시 컨테이너는 애플리케이션과 동일한 pod에 있으므로 애플리케이션이 localhost를 통해 프록시에 연결하여 보안과 성능을 향상시킬 수 있습니다. 자세히 알아보기

Cloud SQL 프록시에 대한 자세한 내용은 Cloud SQL 프록시 정보를 참조하세요. pod를 이용한 작업에 대한 자세한 내용은 Kubernetes 문서의 pod 개요를 참조하세요.

Cloud SQL 프록시를 사용하여 연결하려면 다음이 필요합니다.

  1. Cloud SQL 인스턴스의 인스턴스 연결 이름

    인스턴스 연결 이름은 Cloud Console의 Cloud SQL 인스턴스 세부정보 페이지 또는 gcloud sql instances describe 명령어에서 볼 수 있습니다.

  2. Cloud SQL 인스턴스에 대한 적절한 권한을 가진 서비스 계정과 연결된 키 파일의 위치

    자세한 내용은 서비스 계정 만들기를 참조하세요.

  3. Cloud SQL Admin API를 사용 설정합니다.

    API 사용 설정

프록시에 서비스 계정 제공

Google Kubernetes Engine에서 Cloud SQL 프록시를 실행하는 첫 단계는 애플리케이션을 나타내는 서비스 계정을 만드는 것입니다. 어디서나 동일한 서비스 계정을 사용하는 대신 각 애플리케이션에 고유한 서비스 계정을 만드는 것이 좋습니다. 이 모델은 애플리케이션별로 권한을 제한할 수 있으므로 더 안전합니다.

애플리케이션의 서비스 계정은 다음 기준을 충족해야 합니다.

  • Cloud SQL Admin API가 사용 설정된 프로젝트에 속합니다.
  • 연결하려는 인스턴스가 포함된 프로젝트의 Cloud SQL 클라이언트 IAM 역할(또는 이에 상응)이 부여됨
  • 비공개 IP를 사용하여 연결하는 경우 Cloud SQL 인스턴스와 동일한 VPC에서 VPC 기반 GKE 클러스터를 사용해야 합니다.

Cloud SQL 프록시에 서비스 계정을 제공하도록 GKE를 구성해야 합니다. 권장되는 두 가지 방법은 워크로드 아이덴티티 또는 서비스 계정 키 파일입니다.

작업 부하 ID

Google Kubernetes Engine을 사용하는 경우 GKE의 워크로드 아이덴티티 기능을 사용하는 것이 좋습니다. 이 방법을 사용하면 Kubernetes 서비스 계정(KSA)을 Google 서비스 계정(GSA)에 결합할 수 있습니다. 그러면 일치하는 KSA를 사용하는 애플리케이션에서 GSA에 액세스할 수 있습니다.

Google 서비스 계정(GSA)은 Google Cloud에서 애플리케이션을 나타내는 IAM ID입니다. 이와 마찬가지로 Kubernetes 서비스 계정(KSA)은 Google Kubernetes Engine 클러스터에서 애플리케이션을 나타내는 ID입니다.

워크로드 아이덴티티는 KSA를 GSA에 결합하기 때문에 해당 KSA를 사용한 모든 배포에서 Google Cloud와의 상호작용 시 GSA로 인증하게 됩니다.

  1. 클러스터에 워크로드 아이덴티티를 사용 설정합니다.
  2. 일반적으로 각 애플리케이션에는 KSA와 GSA 쌍으로 표시되는 고유 ID가 있습니다. kubectl apply -f service-account.yaml을 실행하여 애플리케이션의 KSA를 만듭니다.

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: <YOUR-KSA-NAME> # TODO(developer): replace these values
  3. YOUR-GSA-NAMEYOUR-KSA-NAME 간에 IAM binding을 사용 설정합니다.

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:<YOUR-GCP-PROJECT>.svc.id.goog[<YOUR-K8S-NAMESPACE>/<YOUR-KSA-NAME>]" \
      <YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com
    
  4. YOUR-KSA-NAME에 주석을 추가하여 binding을 완료합니다.

    kubectl annotate serviceaccount \
       <YOUR-KSA-NAME> \
       iam.gke.io/gcp-service-account=<YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com
    
  5. 마지막으로 k8s 객체의 서비스 계정을 지정해야 합니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: <YOUR-DEPLOYMENT-NAME>
    spec:
      selector:
        matchLabels:
          app: <YOUR-APPLICATION-NAME>
      template:
        metadata:
          labels:
            app: <YOUR-APPLICATION-NAME>
        spec:
          serviceAccountName: <YOUR-KSA-NAME>

서비스 계정 키 파일

또는 워크로드 아이덴티티를 사용할 수 없는 경우에 권장되는 패턴은 서비스 계정 키 파일을 Cloud SQL 프록시 pod에 마운트하고 -credential_file 플래그를 사용하는 것입니다.

  1. 서비스 계정 키의 사용자 인증 정보 파일을 만듭니다.

    gcloud iam service-accounts keys create ~/key.json \
      --iam-account <YOUR-SA-NAME>@project-id.iam.gserviceaccount.com
    
  2. 서비스 계정 키를 k8s 보안 비밀로 바꿉니다.

    kubectl create secret generic <YOUR-SA-SECRET> \
    --from-file=service_account.json=~/key.json
    
  3. k8s 객체의 spec: 아래에 보안 비밀을 볼륨으로 마운트합니다.

    volumes:
    - name: <YOUR-SA-SECRET-VOLUME>
      secret:
        secretName: <YOUR-SA-SECRET>
    
  4. 다음 섹션의 안내에 따라 프록시 pod의 볼륨에 액세스합니다.

프록시를 사이드카로 실행

애플리케이션과 pod를 공유하는 추가 컨테이너로 sidecar 패턴에서 프록시를 실행하는 것이 좋습니다. 다음과 같은 이유로 인해 별도의 서비스로 실행하는 것이 좋습니다.

  • SQL 트래픽이 로컬로 노출되지 않도록 합니다. 프록시는 발신 연결에 암호화를 제공하지만 수신 연결에 대한 노출을 제한해야 합니다.
  • 단일 장애점을 방지합니다. 데이터베이스에 대한 각 애플리케이션의 액세스는 다른 애플리케이션에 대해 독립적이므로 복원력이 더 우수합니다.
  • 프록시에 대한 액세스를 제한하여 데이터베이스를 전체 클러스터에 노출하지 않고 애플리케이션별로 IAM 권한을 사용할 수 있습니다.
  • 리소스 요청 범위를 더 정확하게 지정할 수 있습니다. 프록시는 사용량에 비례하여 리소스를 소비하므로 이 패턴을 사용하면 확장되는 애플리케이션에 맞게 리소스 범위를 더 정확하게 지정하고 요청할 수 있습니다.
  1. containers:의 pod 구성에 Cloud SQL 프록시를 추가합니다.

    - name: cloud-sql-proxy
      # It is recommended to use the latest version of the Cloud SQL proxy
      # Make sure to update on a regular schedule!
      image: gcr.io/cloudsql-docker/gce-proxy:1.17
      command:
        - "/cloud_sql_proxy"
    
        # If connecting from a VPC-native GKE cluster, you can use the
        # following flag to have the proxy connect over private IP
        # - "-ip_address_types=PRIVATE"
    
        # Replace DB_PORT with the port the proxy should listen on
        # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433
        - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>"
      securityContext:
        # The default Cloud SQL proxy image runs as the
        # "nonroot" user and group (uid: 65532) by default.
        runAsNonRoot: true

    서비스 계정 키를 사용하는 경우 보안 비밀 볼륨을 지정하고 명령어에 -credential_file 플래그를 추가합니다.

      # This flag specifies where the service account key can be found
      - "-credential_file=/secrets/service_account.json"
    securityContext:
      # The default Cloud SQL proxy image runs as the
      # "nonroot" user and group (uid: 65532) by default.
      runAsNonRoot: true
    volumeMounts:
    - name: <YOUR-SA-SECRET-VOLUME>
      mountPath: /secrets/
      readOnly: true
  2. 마지막으로 명령어 섹션에서 지정한 DB_PORT127.0.0.1을 사용하여 연결하도록 애플리케이션을 구성합니다.

구성 파일의 전체 예시:

워크로드 아이덴티티로 프록시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      serviceAccountName: <YOUR-KSA-NAME>
      containers:
      - name: <YOUR-APPLICATION-NAME>
        # ... other container configuration
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: database
      - name: cloud-sql-proxy
        # It is recommended to use the latest version of the Cloud SQL proxy
        # Make sure to update on a regular schedule!
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        command:
          - "/cloud_sql_proxy"

          # If connecting from a VPC-native GKE cluster, you can use the
          # following flag to have the proxy connect over private IP
          # - "-ip_address_types=PRIVATE"

          # Replace DB_PORT with the port the proxy should listen on
          # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433
          - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>"
        securityContext:
          # The default Cloud SQL proxy image runs as the
          # "nonroot" user and group (uid: 65532) by default.
          runAsNonRoot: true

서비스 계정 키로 프록시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      containers:
      - name: <YOUR-APPLICATION-NAME>
        # ... other container configuration
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: database
      - name: cloud-sql-proxy
        # It is recommended to use the latest version of the Cloud SQL proxy
        # Make sure to update on a regular schedule!
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        command:
          - "/cloud_sql_proxy"

          # If connecting from a VPC-native GKE cluster, you can use the
          # following flag to have the proxy connect over private IP
          # - "-ip_address_types=PRIVATE"

          # Replace DB_PORT with the port the proxy should listen on
          # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433
          - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>"

          # This flag specifies where the service account key can be found
          - "-credential_file=/secrets/service_account.json"
        securityContext:
          # The default Cloud SQL proxy image runs as the
          # "nonroot" user and group (uid: 65532) by default.
          runAsNonRoot: true
        volumeMounts:
        - name: <YOUR-SA-SECRET-VOLUME>
          mountPath: /secrets/
          readOnly: true
      volumes:
      - name: <YOUR-SA-SECRET-VOLUME>
        secret:
          secretName: <YOUR-SA-SECRET>

Cloud SQL 프록시 없이 연결

안전하지는 않지만 프록시 없이 비공개 IP를 사용하여 VPC 네이티브 GKE 클러스터에서 동일한 VPC의 Cloud SQL 인스턴스로 연결할 수 있습니다.

  1. 인스턴스의 비공개 IP 주소로 보안 비밀을 만듭니다.

    kubectl create secret generic <YOUR-PRIVATE-IP-SECRET> \
        --from-literal=db_host=<YOUR-PRIVATE-IP-ADDRESS>
    
  2. 그런 다음 애플리케이션의 컨테이너에 보안 비밀을 추가합니다.

    - name: DB_HOST
      valueFrom:
        secretKeyRef:
          name: <YOUR-PRIVATE-IP-SECRET>
          key: db_host
  3. 마지막으로 애플리케이션을 구성하여 DB_HOST 환경 변수의 IP 주소를 통해 연결합니다. PostgreSQL에 올바른 포트(5432)를 사용해야 합니다.

구성 파일 전체 예시:

프록시 없음 - 비공개 IP

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      containers:
      - name: <YOUR-APPLICATION-NAME>
        # ... other container configuration
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: database
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: <YOUR-PRIVATE-IP-SECRET>
              key: db_host

도움이 필요하신가요? 프록시 문제를 해결하는 데 도움이 필요하면 Cloud SQL 프록시 연결 문제해결 또는 Cloud SQL 지원 페이지를 참조하세요.

다음 단계