PostgreSQL용 Cloud SQL 사용

이 페이지는 App Engine 애플리케이션에서 PostgreSQL용 Cloud SQL 인스턴스에 연결하고 Cloud SQL을 읽고 쓰는 방법을 보여 줍니다. Cloud SQL은 Google 클라우드에 위치한 SQL 데이터베이스입니다.

Cloud SQL에 대한 자세한 내용은 Cloud SQL 문서를 참조하세요. Cloud SQL 가격 및 한도에 대한 자세한 내용은 Cloud SQL 가격 페이지를 참조하세요. App Engine 애플리케이션에도 App Engine 할당량이 적용됩니다.

시작하기 전에

  1. GCP 콘솔에서 GCP 프로젝트를 만들거나 선택한 후 프로젝트에 App Engine 애플리케이션이 포함되어 있고 결제가 사용 설정되어 있는지 확인합니다.
    App Engine으로 이동

    프로젝트에 App Engine 애플리케이션이 이미 있고 결제가 사용 설정되어 있으면 대시보드가 열립니다. 그렇지 않은 경우, 표시되는 메시지를 따라 지역을 선택하고 결제를 사용 설정합니다.

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

    API 사용 설정

  3. gcloud 도구로 앱을 배포하려면 Cloud SDK를 다운로드, 설치, 초기화해야 합니다.
    SDK 다운로드

Cloud SQL 인스턴스 구성

Cloud SQL 인스턴스를 만들고 구성하려면 다음 단계를 따르세요.

  1. PostgreSQL용 Cloud SQL 인스턴스를 만듭니다.
  2. 아직 Cloud SQL 인스턴스의 기본 사용자 비밀번호를 설정하지 않은 경우, 다음 명령어를 실행하여 설정합니다.
    gcloud sql users set-password postgres no-host --instance [INSTANCE_NAME] --password [PASSWORD]
    
  3. 기본 사용자로 사용하지 않으려면 사용자를 만듭니다.
  4. 인스턴스의 연결 이름을 기록합니다.
    gcloud sql instances describe [INSTANCE_NAME]
    

    예를 들면 다음과 같습니다.

    connectionName: project1:us-central1:instance1
    

    Google Cloud Platform 콘솔의 인스턴스 세부정보 페이지에서도 이 값을 확인할 수 있습니다.

  5. Cloud SQL 인스턴스에서 데이터베이스를 만듭니다.
    gcloud sql databases create [DATABASE_NAME] --instance=[INSTANCE_NAME]
    
    데이터베이스 만들기 및 관리에 대한 자세한 내용은 Cloud SQL 문서를 참조하세요.

App Engine 액세스 권한 부여

App Engine 애플리케이션과 Cloud SQL 인스턴스가 서로 다른 Google Cloud Platform 프로젝트에 있는 경우, 서비스 계정을 사용하여 App Engine 애플리케이션이 Cloud SQL에 액세스할 수 있도록 허용해야 합니다.

이 서비스 계정은 App Engine 애플리케이션을 나타내며 Google Cloud Platform 프로젝트 생성 시 기본적으로 생성됩니다.

  1. App Engine 애플리케이션이 Cloud SQL 인스턴스와 동일한 프로젝트에 있는 경우, 이 섹션을 건너뛰고 로컬 환경 설정으로 이동할 수 있습니다. 그렇지 않은 경우, 다음 단계를 진행합니다.
  2. App Engine 애플리케이션에 연결된 서비스 계정을 확인합니다. 기본 App Engine 서비스 계정 이름은 [PROJECT-ID]@appspot.gserviceaccount.com입니다.

    IAM 권한 페이지에서 App Engine 서비스 계정을 확인할 수 있습니다. Cloud SQL 인스턴스가 아닌 App Engine 애플리케이션의 프로젝트를 선택해야 합니다.

    IAM 권한 페이지로 이동

  3. Google Cloud Platform 콘솔의 IAM & Admin Projects(IAM 및 관리자 프로젝트) 페이지로 이동합니다.

    IAM & Admin Projects(IAM 및 프로젝트 관리) 페이지로 이동

  4. Cloud SQL 인스턴스가 포함된 프로젝트를 선택합니다.
  5. 서비스 계정 이름을 검색합니다.
  6. 이미 서비스 계정이 있고 이 계정의 역할에 cloudsql.instances.connect 권한이 포함되어 있는 경우, 로컬 환경 설정을 진행할 수 있습니다.

    Cloud SQL Client, Cloud SQL Editor, Cloud SQL Admin 역할 모두 이전 EditorOwner 프로젝트 역할과 마찬가지로 필요한 권한을 제공합니다.

  7. 그렇지 않은 경우, 추가를 클릭하여 서비스 계정을 추가합니다.
  8. 구성원 추가 대화상자에서 서비스 계정 이름을 지정하고 cloudsql.instances.connect 권한이 있는 역할을 선택합니다(뷰어를 제외한 모든 Cloud SQL 사전 정의 역할 선택 가능).

    또는 프로젝트 > 편집자를 선택하여 기본 편집자 역할을 사용할 수 있지만, 이 편집자 역할은 Google Cloud Platform 전반의 권한을 포함하고 있습니다.

    이러한 역할이 보이지 않는 경우, Google Cloud Platform 사용자에게 resourcemanager.projects.setIamPolicy 권한이 없는 것일 수 있습니다. Google Cloud Platform 콘솔의 IAM 페이지로 이동하고 사용자 ID를 검색하여 권한을 확인할 수 있습니다.

  9. 추가를 클릭합니다.

    이제 지정된 역할을 가진 서비스 계정이 표시됩니다.

로컬 환경 설정

배포된 애플리케이션은 App Engine 런타임 환경에 기본 제공되는 Cloud SQL 프록시를 사용하여 Cloud SQL 인스턴스와 통신합니다. 하지만 애플리케이션을 로컬에서 테스트하려면 Cloud SQL 프록시의 로컬 복사본을 개발 환경에 설치하여 사용해야 합니다.

데이터베이스 또는 GCP 콘솔용 관리 클라이언트를 사용하여 Cloud SQL 인스턴스에서 기본적인 관리 작업을 수행할 수 있습니다.

  1. 로컬 머신에서 프록시를 사용하여 연결하도록 gcloud 도구를 인증합니다.

    gcloud auth application-default login
    
  2. Cloud SQL 프록시를 설치합니다.

    Linux 64비트

    1. 프록시를 다운로드합니다.
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
      
    2. 프록시 실행 파일을 만듭니다.
      chmod +x cloud_sql_proxy
      

    Linux 32비트

    1. 프록시를 다운로드합니다.
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
      
    2. 프록시 실행 파일을 만듭니다.
      chmod +x cloud_sql_proxy
      

    macOS 64비트

    1. 프록시를 다운로드합니다.
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
      
    2. 프록시 실행 파일을 만듭니다.
      chmod +x cloud_sql_proxy
      

    macOS 32비트

    1. 프록시를 다운로드합니다.
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
      
    2. 프록시 실행 파일을 만듭니다.
      chmod +x cloud_sql_proxy
      

    Windows 64비트

    https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe를 마우스 오른쪽 버튼으로 클릭하고 'Save link as...(다른 이름으로 링크 저장)'를 선택하여 프록시를 다운로드한 후 cloud_sql_proxy.exe로 이름을 바꿉니다.

    Windows 32비트

    https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe를 마우스 오른쪽 버튼으로 클릭하고 'Save link as...(다른 이름으로 링크 저장)'을 선택하여 프록시를 다운로드한 후 cloud_sql_proxy.exe로 이름을 바꿉니다.
    사용 중인 운영 체제가 여기에 없으면 소스에서 프록시를 컴파일할 수도 있습니다.

  3. 프록시를 실행합니다.

    언어 및 환경에 따라 TCP 소켓 또는 Unix 소켓을 사용하여 프록시를 시작할 수 있습니다.

    TCP 소켓

    1. 인스턴스 세부정보 페이지에서 인스턴스 연결 이름을 복사합니다.
    2. 서비스 계정을 사용하여 프록시를 인증하는 경우, 서비스 계정 생성 시 생성된 비공개 키 파일의 클라이언트 머신 위치를 메모합니다.
    3. 프록시를 시작합니다.

      사용할 수 있는 몇 가지 프록시 호출 문자열은 다음과 같습니다.

      • Cloud SDK 인증 사용:
        ./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432
        
        지정된 포트는 로컬 데이터베이스 서버 등에서 사용되지 않아야 합니다.
      • 서비스 계정 사용 및 인스턴스 사양 명시적 지정 (프로덕션 환경에서 권장됨):
        ./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432 \
                          -credential_file=<PATH_TO_KEY_FILE> &
        

      프록시 옵션에 대한 자세한 내용은 프록시 인증 옵션인스턴스 지정 옵션을 참조하세요.

    Unix 소켓

    1. 명시적 인스턴스 지정을 사용하는 경우, 인스턴스 세부정보 페이지에서 인스턴스 연결 이름을 복사합니다.
    2. 프록시 소켓이 위치할 디렉토리를 만듭니다.
      sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
    3. 서비스 계정을 사용하여 프록시를 인증하는 경우, 서비스 계정 생성 시 생성된 비공개 키 파일의 클라이언트 머신 위치를 메모합니다.
    4. 새 터미널 창을 열고 프록시를 시작합니다.

      사용할 수 있는 몇 가지 프록시 호출 문자열은 다음과 같습니다.

      • 서비스 계정 사용 및 인스턴스 사양 명시적 지정 (프로덕션 환경에서 권장됨):
        ./cloud_sql_proxy -dir=/cloudsql -instances=<INSTANCE_CONNECTION_NAME> \
                          -credential_file=<PATH_TO_KEY_FILE> &
      • Cloud SDK 인증 및 자동 인스턴스 검색 사용:
        ./cloud_sql_proxy -dir=/cloudsql &

      프록시 출력을 다른 프로그램의 출력과 별도로 모니터링할 수 있도록 자체 터미널 내에서 프록시를 시작하는 것이 가장 좋습니다.

      프록시 옵션에 대한 자세한 내용은 프록시 인증 옵션인스턴스 지정 옵션을 참조하세요.

  4. 로컬 복사본을 설치하고 프록시 또는 IP 주소로 연결하여 관리 클라이언트를 사용할 수 있습니다.

    자세한 내용은 Cloud SQL 프록시를 사용하여 psql 클라이언트 연결IP 주소를 사용하여 psql 클라이언트 연결을 참조하세요.

연결 문자열 설정 및 라이브러리 추가

  1. 로컬 테스트를 위한 연결을 지원하도록 로컬 환경을 설정합니다.

    예를 들어 제공된 코드 샘플의 경우, 다음 명령어를 입력합니다.

    export SQL_USER=[YOUR_SQL_USER]
    export SQL_PASSWORD=[YOUR_SQL_PASSWORD]
    export SQL_DATABASE=[YOUR_SQL_DATABASE]
    npm install
    

    기본적으로 앱을 로컬에서 실행하면 앱이 TCP 소켓을 사용하여 연결을 시도합니다. Unix 소켓을 사용하도록 프록시를 구성한 경우에는 다음 추가 환경 변수를 설정하세요.

    export INSTANCE_CONNECTION_NAME=[YOUR_INSTANCE_CONNECTION_NAME]
    

    이러한 환경 변수는 연결을 설정하는 데 사용됩니다.

    const config = {
      user: process.env.SQL_USER,
      password: process.env.SQL_PASSWORD,
      database: process.env.SQL_DATABASE
    };
    
    if (process.env.INSTANCE_CONNECTION_NAME && process.env.NODE_ENV === 'production') {
      config.host = `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}`;
    }
    
    // Connect to the database
    const knex = Knex({
      client: 'pg',
      connection: config
    });

  2. 앱 배포 시 앱이 Cloud SQL 인스턴스에 연결할 수 있도록 허용하려면 Cloud SQL의 사용자, 비밀번호, 데이터베이스, 인스턴스 연결 이름 변수를 app.flexible.yaml 파일의 관련 환경 변수에 추가합니다. 배포된 애플리케이션은 Unix 소켓을 통해 연결됩니다.

    # The following env variables may contain sensitive information that grants
    # anyone access to your database. Do not add this file to your source control.
    env_variables:
      SQL_USER: YOUR_SQL_USER
      SQL_PASSWORD: YOUR_SQL_PASSWORD
      SQL_DATABASE: YOUR_SQL_DATABASE
      # e.g. my-awesome-project:us-central1:my-cloud-sql-instance
      INSTANCE_CONNECTION_NAME: YOUR_INSTANCE_CONNECTION_NAME
  3. Cloud SQL 인스턴스 연결 이름을 사용하여 beta_settings 섹션을 app.flexible.yaml에 추가합니다.

    beta_settings:
      # The connection name of your instance, available by using
      # 'gcloud beta sql instances describe [INSTANCE_NAME]' or from
      # the Instance details page in the Google Cloud Platform Console.
      cloud_sql_instances: YOUR_INSTANCE_CONNECTION_NAME

    1. Node.js PostgreSQL 클라이언트 라이브러리를 애플리케이션의 package.json에 추가합니다. 예를 들어, 제공된 코드 샘플은 pg 패키지를 사용하는 Knex.js를 드라이버로 사용합니다.
      "dependencies": {
        "async": "2.6.0",
        "express": "4.16.2",
        "knex": "0.14.4",
        "pg": "7.4.1",
        "prompt": "1.0.0"
      },

    샘플 코드 실행

    아래의 server.js 샘플은 Cloud SQL 인스턴스에서 방문자 로그를 만듭니다.

    샘플을 실행하기 전에 createTables.js를 실행하여 필요한 표를 만들고 데이터베이스가 제대로 구성되었는지 확인합니다.

    const Knex = require('knex');
    const prompt = require('prompt');
    
    const FIELDS = ['user', 'password', 'database'];
    
    prompt.start();
    
    // Prompt the user for connection details
    prompt.get(FIELDS, (err, config) => {
      if (err) {
        console.error(err);
        return;
      }
    
      // Connect to the database
      const knex = Knex({ client: 'pg', connection: config });
    
      // Create the "visits" table
      knex.schema.createTable('visits', (table) => {
        table.increments();
        table.timestamp('timestamp');
        table.string('userIp');
      })
        .then(() => {
          console.log(`Successfully created 'visits' table.`);
          return knex.destroy();
        })
        .catch((err) => {
          console.error(`Failed to create 'visits' table:`, err);
          if (knex) {
            knex.destroy();
          }
        });
    });

    다음 샘플은 Cloud SQL에 방문 정보를 쓴 다음 마지막 10회 방문을 읽고 반환합니다.

    const express = require('express');
    const Knex = require('knex');
    const crypto = require('crypto');
    
    const app = express();
    app.enable('trust proxy');
    
    const knex = connect();
    
    function connect () {
      const config = {
        user: process.env.SQL_USER,
        password: process.env.SQL_PASSWORD,
        database: process.env.SQL_DATABASE
      };
    
      if (process.env.INSTANCE_CONNECTION_NAME && process.env.NODE_ENV === 'production') {
        config.host = `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}`;
      }
    
      // Connect to the database
      const knex = Knex({
        client: 'pg',
        connection: config
      });
    
      return knex;
    }
    
    /**
     * Insert a visit record into the database.
     *
     * @param {object} knex The Knex connection object.
     * @param {object} visit The visit record to insert.
     * @returns {Promise}
     */
    function insertVisit (knex, visit) {
      return knex('visits').insert(visit);
    }
    
    /**
     * Retrieve the latest 10 visit records from the database.
     *
     * @param {object} knex The Knex connection object.
     * @returns {Promise}
     */
    function getVisits (knex) {
      return knex.select('timestamp', 'userIp')
        .from('visits')
        .orderBy('timestamp', 'desc')
        .limit(10)
        .then((results) => {
          return results.map((visit) => `Time: ${visit.timestamp}, AddrHash: ${visit.userIp}`);
        });
    }
    
    app.get('/', (req, res, next) => {
      // Create a visit record to be stored in the database
      const visit = {
        timestamp: new Date(),
        // Store a hash of the visitor's ip address
        userIp: crypto.createHash('sha256').update(req.ip).digest('hex').substr(0, 7)
      };
    
      insertVisit(knex, visit)
        // Query the last 10 visits from the database.
        .then(() => getVisits(knex))
        .then((visits) => {
          res
            .status(200)
            .set('Content-Type', 'text/plain')
            .send(`Last 10 visits:\n${visits.join('\n')}`)
            .end();
        })
        .catch((err) => {
          next(err);
        });
    });
    
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
      console.log(`App listening on port ${PORT}`);
      console.log('Press Ctrl+C to quit.');
    });

    테스트 및 배포

    1. 애플리케이션을 로컬에서 테스트하려면 다음 명령어를 입력합니다.

      npm start
      

    2. 로컬 테스트 후 앱을 App Engine에 배포합니다.

      gcloud app deploy app.flexible.yaml
      

    3. 브라우저를 시작하고 http://[YOUR_PROJECT_ID].appspot.com에서 앱을 보려면 다음 명령어를 실행합니다.

      gcloud app browse
      
이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...

Node.js 문서용 App Engine 가변형 환경