启动 PGAdapter

本页介绍如何在 Spanner 中启动 PGAdapter。如需了解 PGAdapter,请参阅 PGAdapter 简介。如需获取 PGAdapter 二进制文件,请参阅获取 PGAdapter

您可以通过以下方式启动 PGAdapter:

  • 作为一个独立进程
  • 在 Docker 容器内
  • 在 Cloud Run 上
  • 将 PGAdapter 用作边车代理(例如,在 Kubernetes 集群中)
  • 在 Java 应用中进行进程内处理

准备工作

在启动 PGAdapter 之前,请确保您已在运行 PGAdapter 的机器上使用用户帐号或服务帐号进行身份验证。如果您使用的是服务帐号,则必须知道 JSON 密钥文件(凭据文件)的位置。然后,您可以使用 PGAdapter -c 选项或通过设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量来指定凭据路径。

如需了解详情,请参阅以下主题:

选择运行 PGAdapter 的方法

您可以在 Docker 容器内、Cloud Run 中或 Java 应用的进程内启动 PGAdapter。启动 PGAdapter 时,您需要指定要连接的项目、Spanner 实例和数据库。您还可以指定 JSON 格式的凭据文件(密钥文件)的路径。

独立式

使用以下命令下载 PGAdapter。

wget https://storage.googleapis.com/pgadapter-jar-releases/pgadapter.tar.gz \
  && tar -xzvf pgadapter.tar.gz

使用以下命令启动 PGAdapter。

java -jar pgadapter.jar -p PROJECT_NAME -i INSTANCE_NAME -d DATABASE_NAME \
  -c CREDENTIALS_FILE_PATH \
  ADDITIONAL_OPTIONS

以下选项为必需:

-p project_name
正在运行 Spanner 数据库的项目的名称。
-i instance_name
Spanner 实例名称。
-d database_name
要连接的数据库的名称。

以下选项为可选:

-r databaseRole=database_role
要用于会话的数据库角色。如需了解详情,请参阅使用 PGAdapter 授权
-c credentials_file_path
包含 JSON 格式的服务账号凭据的密钥文件完整路径。如果未设置此选项,则系统会从 GOOGLE_APPLICATION_CREDENTIALS 环境变量指定的路径中读取凭据。

如需了解如何创建服务帐号和下载 JSON 格式的密钥文件,请参阅 创建服务帐号

请确保您向服务账号授予足够的凭据,以允许其访问数据库。

如果您首先使用以下命令通过 Google Cloud CLI 进行身份验证,则可以省略此选项:

gcloud auth application-default login

如需了解详情,请参阅 设置身份验证和授权

-s port
PGAdapter 侦听的端口。默认为 5432(即默认的 PostgreSQL 端口)。
-v version_number

要在连接过程中公开给客户端的 PostgreSQL 的版本号。默认值为 14.1

某些 PostgreSQL 应用和驱动程序会根据此版本号启用额外的功能。Spanner 可能不支持这些功能。如需查看受支持客户端的完整列表,请参阅 驱动程序和客户端

-x

启用 localhost 以外的主机发起的连接。在独立模式下启动 PGAdapter 时请勿使用。只有在 Docker 容器内启动时才能使用。

默认情况下,出于安全考虑,PGAdapter 仅接受 localhost 发起的连接。

下面的简单示例使用默认应用凭据在端口 5432 上以独立模式启动 PGAdapter。

java -jar pgadapter.jar \
  -p my-project \
  -i my-instance \
  -d my-database \
  -s 5432
            

Docker

使用以下命令启动 PGAdapter。

docker run -d -p HOST-PORT:DOCKER-PORT \
    -v CREDENTIALS_FILE_PATH:/acct_credentials.json \
    gcr.io/cloud-spanner-pg-adapter/pgadapter:latest \
    -p PROJECT_NAME -i INSTANCE_NAME -d DATABASE_NAME  \
    -c /acct_credentials.json -x OTHER_PGAdapter_OPTIONS

除了用于指定项目、实例、数据库和凭据的 PGAdapter 选项之外,还需要使用以下选项:

-p 127.0.0.1:HOST-PORT:DOCKER-PORT

此 Docker 选项会将 Docker 容器内部的端口 DOCKER-PORT 映射到容器外部的端口 HOST-PORTDOCKER-PORT 必须与 PGAdapter 在容器内部的配置方式相匹配。默认值为 5432。HOST-PORT 是 Docker 应在容器外部侦听连接请求的端口。它必须始终是 localhost 上的可用端口。

如需了解详情,请参阅 Docker 文档中的发布或公开端口(-p、--expos)

-v CREDENTIALS_FILE_PATH:in_container_mount_point

此 Docker 选项绑定会装载一个共享卷。它将容器外部的主机路径映射到容器内的一个卷(装载点)。主机路径和容器路径之间使用英文冒号 (:) 分隔。

通过此选项,PGAdapter 可以访问容器之外的 JSON 凭据文件。在前面的示例中,-c 选项引用容器内的装载点。此示例将容器内装载点命名为 /acct_credentials.json。您可以随意为其命名。

如需了解详情,请参阅 Docker 文档中的卷(共享文件系统)

-x

启用 localhost 以外的主机发起的连接。之所以需要这样做,是因为映射到主机端口的容器内部端口不会对 PGAdapter 显示为 localhost。

以下选项是可选的:

-r databaseRole=database_role
要用于会话的数据库角色。如需了解详情,请参阅使用 PGAdapter 授权

在以下示例中,Docker 端口和主机端口均设置为 PostgreSQL 数据库服务默认端口 5432。

docker run -d -p 127.0.0.1:5432:5432 \
    -v /tmp/credentials.json:/acct_credentials.json \
    gcr.io/cloud-spanner-pg-adapter/pgadapter:latest \
    -p my_project -i my_instance -d my_database \
    -c /acct_credentials.json -x

Cloud Run

您无法在 Cloud Run 上将 PGAdapter 作为独立服务进行部署,但可以将其部署为边车代理。

与以单独的服务运行 PGAdapter 相比,建议以 Sidecar 模式运行 PGAdapter,原因如下:
  • 防止单点故障。每个应用对您数据库的访问都独立于其他应用,因而更具弹性。
  • PGAdapter 实例的数量会根据应用实例的数量自动扩容。

PGAdapter GitHub 代码库包含针对各种编程语言的 一些使用 Cloud Run 和 PGAdapter 作为边车代理的有效示例应用

以下配置文件显示了如何将 PGAdapter 作为边车代理添加到 Cloud Run:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
    # This example uses an in-memory volume for Unix domain sockets.
    # This is a Cloud Run beta feature.
    run.googleapis.com/launch-stage: BETA
  name: pgadapter-sidecar-example
spec:
  template:
    metadata:
      annotations:
        run.googleapis.com/execution-environment: gen1
        # This registers 'pgadapter' as a dependency of 'app' and ensures that pgadapter starts
        # before the app container.
        run.googleapis.com/container-dependencies: '{"app":["pgadapter"]}'
    spec:
      # Create an in-memory volume that can be used for Unix domain sockets.
      volumes:
        - name: sockets-dir
          emptyDir:
            # This directory contains the virtual socket files that are used to
            # communicate between your application and PGAdapter.
            sizeLimit: 50Mi
            medium: Memory
      containers:
        # This is the main application container.
        - name: app
          # Example: europe-north1-docker.pkg.dev/my-test-project/cloud-run-source-deploy/pgadapter-sidecar-example
          image: MY-REGION.pkg.dev/MY-PROJECT/cloud-run-source-deploy/pgadapter-sidecar-example
          # The PGADAPTER_HOST variable is set to point to /sockets, which is the shared in-memory
          # volume that is used for Unix domain sockets.
          env:
            - name: SPANNER_PROJECT
              value: my-project
            - name: SPANNER_INSTANCE
              value: my-instance
            - name: SPANNER_DATABASE
              value: my-database
            - name: PGADAPTER_HOST
              value: /sockets
            - name: PGADAPTER_PORT
              value: "5432"
          ports:
            - containerPort: 8080
          volumeMounts:
            - mountPath: /sockets
              name: sockets-dir
        # This is the PGAdapter sidecar container.
        - name: pgadapter
          image: gcr.io/cloud-spanner-pg-adapter/pgadapter
          volumeMounts:
            - mountPath: /sockets
              name: sockets-dir
          args:
            - -dir /sockets
            - -x
          # Add a startup probe that checks that PGAdapter is listening on port 5432.
          startupProbe:
            initialDelaySeconds: 10
            timeoutSeconds: 10
            periodSeconds: 10
            failureThreshold: 3
            tcpSocket:
              port: 5432
          

Sidecar 代理

例如,您可以在 Kubernetes 集群中将 PGAdapter 用作边车代理。Kubernetes Sidecar 容器与 Pod 中的主容器并行运行。

与以单独的服务运行 PGAdapter 相比,建议以 Sidecar 模式运行 PGAdapter,原因如下:

  • 防止单点故障。每个应用对您数据库的访问都独立于其他应用,因而更具弹性。
  • 由于 PGAdapter 消耗的资源与用量呈线性关系,因此借助此模式,您可以更准确地确定和请求资源,以便在应用扩缩时匹配应用。

以下配置文件展示了如何将 PGAdapter 作为边车代理添加到 Kubernetes 集群中:

containers:
- name: pgadapter
  image: gcr.io/cloud-spanner-pg-adapter/pgadapter
  ports:
    - containerPort: 5432
  args:
    - "-p my-project"
    - "-i my-instance"
    - "-d my-database"
    - "-x"
  resources:
    requests:
      # PGAdapter's memory use scales linearly with the number of active
      # connections. Fewer open connections will use less memory. Adjust
      # this value based on your application's requirements.
      memory: "512Mi"
      # PGAdapter's CPU use scales linearly with the amount of IO between
      # the database and the application. Adjust this value based on your
      # application's requirements.
      cpu: "1"

PGAdapter GitHub 代码库包含分步指南和示例应用。此示例包含有关将 Workload Identity 与 PGAdapter 配合使用的说明。

Java 进程内

使用您的 Java 代码创建并启动 PGAdapter 实例。 这是 Java 应用的推荐设置。

如果您使用服务帐号进行身份验证,请确保将 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为凭据文件的路径。

  1. google-cloud-spanner-pgadapter 作为依赖项添加到您的项目中。如需了解详情,请参阅获取 PGAdapter
  2. <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-spanner-pgadapter</artifactId>
      <version>0.33.1</version>
    </dependency>
  3. 使用 com.google.cloud.spanner.pgadapter.ProxyServer 类构建一个服务器。
  4. /**
      * Starts PGAdapter in-process and returns a reference to the server. Use this reference to
      * gracefully shut down the server when your application shuts down.
      *
      * @param project the Google Cloud project that PGAdapter should connect to
      * @param instance the Spanner instance that PGAdapter should connect to
      * @param credentialsFile the full path of a credentials file that PGAdapter should use, or 
      *     null if PGAdapter should use the application default credentials
      */
    static Server startPGAdapter(String project, String instance, String credentialsFile) {
      OptionsMetadata.Builder builder =
          OptionsMetadata.newBuilder()
              .setProject(project)
              .setInstance(instance)
              // Start PGAdapter on any available port.
              .setPort(0);
      if (credentialsFile != null) {
        builder.setCredentialsFile(credentialsFile);
      }
      ProxyServer server = new ProxyServer(builder.build());
      server.startServer();
      server.awaitRunning();
    
      return new PGAdapter(server);
    }
                  

PGAdapter GitHub 代码库包含一个完整的示例应用

后续步骤