本文档介绍了如何使用 PGAdapter 连接到 Spanner Omni。您可以配置 PGAdapter 以建立安全连接。 PGAdapter 支持纯文本、 传输层安全协议 (TLS)、 和 双向 TLS (mTLS) 安全模式。这些模式通过提供不同级别的加密和身份验证来保护传输中的数据。每种安全模式都需要特定的客户端配置,以确保数据完整性和机密性。
您可以将 PGAdapter 作为独立进程运行,也可以将其直接集成到应用中。如需进行交互式管理和手动查询执行,请使用 psql 等标准 PostgreSQL 工具连接到数据库。如需构建自动化应用,请使用与 PostgreSQL 兼容的驱动程序,例如:
pgx适用于 Gopsycopg3适用于 Pythonnode-postgres适用于 Node.js
如需查看使用其中一些驱动程序的代码示例,请参阅本文档中的 示例代码。
安全模式
Spanner Omni PGAdapter 支持三种安全模式,这些模式定义了 PGAdapter 与数据库之间的通信加密和身份验证方式。如需使用这些模式,请按照下表中的说明配置客户端选项:
| 安全模式 | 说明 |
|---|---|
| 纯文本 | 通信未加密。 |
| TLS | 通信使用传输层安全协议 (TLS) 加密。此 模式要求您将 Spanner Omni CA 证书添加到 默认 Java 信任库。 |
| mTLS | 通信使用双向 TLS (mTLS) 加密。此模式要求您提供客户端证书和客户端私钥。 |
作为独立进程运行
对于非 Java 应用和标准 PostgreSQL 工具(例如 psql),当您需要手动数据库交互时,请将 PGAdapter 作为独立进程运行。这种方法将代理与应用生命周期分离,让您可以独立管理和更新代理。如需将 PGAdapter 作为独立进程启动,请根据所选的安全模式使用以下配置方法。
使用纯文本模式
如需在纯文本通信模式下启动 PGAdapter,请运行以下命令:
java -jar pgadapter.jar \
-d DATABASE_ID \
-e ENDPOINT \
-r "isExperimentalHost=true;usePlainText=true"
替换以下内容:
DATABASE_ID:Spanner Omni 数据库的 ID,例如test-db。ENDPOINT:Spanner Omni 实例的端点,例如localhost:15000。
使用 TLS 模式
在 Java 应用的进程中以 TLS 模式启动 PGAdapter 之前,您必须将 Spanner Omni CA 证书添加到默认 Java 信任库。如需将现有 CA 证书添加到 Java 信任库,请运行以下命令:
sudo keytool -import -trustcacerts -file ~/.spanner/certs/ca.crt -alias spanner-ca -keystore $JAVA_HOME/lib/security/cacerts
如需在 TLS 模式下启动 PGAdapter,请运行以下命令:
java -Djavax.net.ssl.trustStore=$JAVA_HOME/lib/security/cacerts \
-Djavax.net.ssl.trustStoreType=JKS \
-jar pgadapter.jar \
-d DATABASE_ID \
-e ENDPOINT \
-r "isExperimentalHost=true"
使用 mTLS 模式
在 mTLS 模式下启动 PGAdapter 之前,您必须确保客户端密钥采用 PKCS#8 格式。如需将密钥库中的现有密钥转换为 PKCS#8 格式,请运行以下命令:
openssl pkcs8 -topk8 -in ~/.spanner/certs/client.key -out ~/.spanner/certs/java-client.key -nocrypt
或者,当您使用 Spanner Omni CLI 创建客户端证书和密钥时,请提供 --generate-pkcs8-key 参数以生成 PKCS#8 格式的密钥。
如需在 mTLS 模式下启动 PGAdapter,请运行以下命令:
java -Djavax.net.ssl.trustStore=$JAVA_HOME/lib/security/cacerts \
-Djavax.net.ssl.trustStoreType=JKS \
-jar pgadapter.jar \
-d DATABASE_ID \
-e ENDPOINT \
-r "isExperimentalHost=true;clientCertificate=PATH_TO_CLIENT_CERT;clientKey=PATH_TO_CLIENT_KEY"
替换以下内容:
PATH_TO_CLIENT_CERT:客户端证书文件的路径。PATH_TO_CLIENT_KEY:客户端密钥文件的路径。
使用 psql 连接
使用上述方法之一建立连接后,运行 psql 以管理数据库并执行查询。如需连接到 psql,请使用以下命令:
psql -h PG_HOST -p PG_PORT -U USERNAME -d DATABASE_ID
替换以下内容:
PG_HOST:运行 PGAdapter 的机器的主机名或 IP 地址。如果本地运行,请使用localhost。PG_PORT:PGAdapter 正在运行的端口号。如果您未指定自定义端口,PGAdapter 默认使用端口5432。USERNAME:您的 PostgreSQL 用户名。
在应用的进程中运行
您还可以在应用的进程中启动 PGAdapter。如需建立安全性,请配置 OptionsMetadata 对象。
使用纯文本模式
对于纯文本通信(例如在安全环境中进行本地开发或测试,无需加密开销),请使用以下配置:
OptionsMetadata.Builder builder =
OptionsMetadata.newBuilder()
.setEndpoint("ENDPOINT")
.setUsePlainText();
ProxyServer server = new ProxyServer(builder.build());
server.startServer();
server.awaitRunning();
使用 TLS 模式
对于在本地开发或测试等环境中使用纯文本通信,请使用以下配置:
sudo keytool -import -trustcacerts -file /.spanner/certs/ca.crt -alias spanner-ca -keystore $JAVA_HOME/lib/security/cacerts
如需在进程中建立 TLS 连接,请使用以下配置:
OptionsMetadata.Builder builder =
OptionsMetadata.newBuilder()
.setEndpoint("ENDPOINT");
ProxyServer server = new ProxyServer(builder.build());
server.startServer();
server.awaitRunning();
使用 mTLS 模式
在 Java 应用的进程中以 mTLS 模式启动 PGAdapter 之前,您必须确保客户端密钥采用 PKCS#8 格式。如需将密钥库中的现有密钥转换为 PKCS#8 格式,请运行以下命令:
openssl pkcs8 -topk8 -in ~/.spanner/certs/client.key -out ~/.spanner/certs/java-client.key -nocrypt
或者,当您使用 Spanner Omni CLI 创建客户端证书和密钥时,请提供 --generate-pkcs8-key 参数以生成 PKCS#8 格式的密钥。
如需在进程中建立 mTLS 连接,请使用此配置:
OptionsMetadata.Builder builder =
OptionsMetadata.newBuilder()
.setEndpoint("ENDPOINT")
.useClientCert("PATH_TO_CLIENT_CERT", "PATH_TO_CLIENT_KEY");
ProxyServer server = new ProxyServer(builder.build());
server.startServer();
server.awaitRunning();
示例代码
本部分提供了使用以下与 PostgreSQL 兼容的驱动程序连接到 Spanner Omni 数据库的示例代码:
替换连接字符串中的以下占位符:
- PASSWORD:PostgreSQL 用户的密码。
JDBC
您可以使用 PostgreSQL JDBC 驱动程序连接到 PGAdapter,就像连接到 PostgreSQL 数据库一样。如需连接和查询 Spanner Omni 数据库中的表,请使用以下示例代码:
String jdbcUrl =
"jdbc:postgresql://PG_HOST:PG_PORT/DATABASE_ID";
try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
// Example: Query data
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM Singers")) {
System.out.println("Query Results:");
while (resultSet.next()) {
long id = resultSet.getLong("id");
String name = resultSet.getString("name");
System.out.printf("ID: %d, Name: %s\n", id, name);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Go (pgx)
您可以使用 pgx 连接到 PGAdapter,就像连接到 PostgreSQL 数据库一样。请使用以下示例代码:
// Database connection string
connString := "postgres://USERNAME:PASSWORD@PG_HOST:PG_PORT/DATABASE_ID?sslmode=disable"
ctx := context.Background()
// Connect to PGAdapter
conn, err := pgx.Connect(ctx, connString)
if err != nil {
log.Fatalf("Connection error: %s", err.Error())
}
defer conn.Close(ctx)
// Query all rows from the Singers table
rows, err := conn.Query(ctx, "SELECT id, name FROM Singers")
if err != nil {
log.Fatalf("Query error: %s", err.Error())
}
defer rows.Close()
// Iterate over the result set
fmt.Println("Singers Table Data:")
for rows.Next() {
var id int
var name string
if err := rows.Scan(&id, &name); err != nil {
log.Fatalf("Scan error: %s", err.Error())
}
fmt.Printf("ID: %d, Name: %s\n", id, name)
}
Python (psycopg2 或 psycopg3)
您可以使用 psycopg2 或 psycopg3 连接到 PGAdapter,就像连接到 PostgreSQL 数据库一样。如需连接和查询 Spanner Omni 数据库中的表,请使用以下示例代码:
# psycopg2
import psycopg2
connection = psycopg2.connect(database="DATABASE_ID",
host="PG_HOST",
port=PG_PORT)
cursor = connection.cursor()
cursor.execute('SELECT * FROM Singers')
for row in cursor:
print(row)
cursor.close()
connection.close()
# psycopg3
import psycopg
with psycopg.connect("host=PG_HOST port=PG_PORT dbname=DATABASE_ID sslmode=disable") as conn:
conn.autocommit = True
with conn.cursor() as cur:
cur.execute("SELECT * FROM Singers")
for row in cur:
print(row)
Node.js (node-postgres)
您可以使用
node-postgres连接到 PGAdapter,就像
连接到 PostgreSQL 数据库一样。如需连接和查询 Spanner Omni 数据库中的表,请使用以下示例代码:
const { Client } = require('pg');
const client = new Client({
host: 'PG_HOST',
port: PG_PORT,
database: 'DATABASE_ID',
});
await client.connect();
const res = await client.query("SELECT * FROM Singers");
console.log(res.rows);
await client.end();