在云原生时代,数据库容器化已经不再是“洪水猛兽”,而是变成了提效增能的“倚天剑”。openGauss 作为一款高性能、高安全、高可靠的企业级开源关系型数据库,其与 Kubernetes 的结合是国产基础软件落地的重要一环。
很多朋友在本地玩 openGauss 都是用 Docker 或二进制,但在生产环境中,我们需要的是可自愈、易扩容、免运维的云原生数据库。
今天,我们就来一场实战。我将带你从零开始,使用 Kubernetes 生态的包管理神器 —— Helm,分别部署 openGauss 单机版 和 openGauss 集群版(主备) 。
在本文中,你将学到:
- Helm 的 Chart 结构解析。
- ConfigMap 如何优雅管理数据库配置。
- Service (ClusterIP & NodePort) 如何暴露数据库服务。
- Ingress 虽然主要用于 HTTP,但我会教你如何“骚操作”透传 TCP(适用于管理界面)。
- 最后,使用 Python 编写脚本进行读写验证。
阅读前提:已安装 Kubernetes 集群 (1.19+)、Helm 3 客户端,并配置好 StorageClass。
第一部分:准备工作与 Helm Chart 结构设计
在动手敲命令之前,我们需要明白 Helm 是如何管理复杂应用的。一个标准的 openGauss Helm Chart 目录结构如下:
text
为什么选择 StatefulSet?
数据库是有状态的。StatefulSet 能为 Pod 提供稳定的网络标识(如 opengauss-0)和稳定的持久化存储,这是 Deployment 无法做到的。
第二部分:核心配置 —— ConfigMap 的妙用
在 openGauss 中,配置是灵魂。如果我们每次修改 postgresql.conf 都要重新打包镜像,那就太“传统”了。在 K8s 中,我们使用 ConfigMap 将配置文件剥离出来。
1. 配置 postgresql.conf
我们创建一个 ConfigMap 来存放主配置文件。这里特别注意 监听地址 和 连接数 的设置。
yaml
2. 配置 pg_hba.conf (访问控制)
如果不配置这个,你的 Python 代码会直接 Connection Refused。我们需要允许所有 Pod 网段访问,但强烈建议在生产环境中不要使用 0.0.0.0/0,而是指定集群 CIDR。
yaml
3. 挂载 ConfigMap
在 statefulset.yaml 中,我们需要将 ConfigMap 里的文件挂载到容器内,覆盖默认配置。
yaml
第三部分:网络暴露 —— ClusterIP 与 NodePort
在 K8s 内部,我们使用 ClusterIP 让其他微服务访问;如果需要外部(如你的本地电脑)连接,则需要 NodePort。
1. 内部服务 (ClusterIP)
这是默认的 Service,仅集群内部可见。
yaml
2. 外部访问 (NodePort)
如果你是在云上,通常会搭配云厂商的 LoadBalancer。但在本地或私有云,NodePort 是最简单的暴露方式。
yaml
第四部分:进阶暴露 —— Ingress 的 TCP 配置
通常 Ingress 处理 HTTP(S) 流量,但 nginx-ingress-controller 支持通过 ConfigMap 代理 TCP/UDP 流量。这对于想要通过域名(如 opengauss.internal.example.com)访问数据库非常有用。
实现步骤:
- 修改
nginx-ingress-controller 的 ConfigMap,开放新端口。 - 创建指向数据库 Service 的 Ingress 资源(虽然看起来很怪,但确实可行)。
注意:这需要集群管理员修改 Ingress Controller 的部署,如果只是普通用户,建议直接用 NodePort。
如果你是全栈管理员,可以这样配置 Ingress Controller 的 ConfigMap:
yaml
第五部分:部署 openGauss 单机版
一切就绪,开始实战。假设你已经写好了上述的 Chart,或者使用社区 Chart。
1. 创建 values.yaml
定制我们的单机版参数。
yaml
2. 执行安装
bash
3. 验证
bash
第六部分:部署 openGauss 集群版(主备)
集群版是 openGauss 的高可用形态,通常是一主一备或多备。Helm 可以通过脚本和启动探针自动配置主备关系。
1. 集群配置难点
- Datanode 角色:需要区分谁是 Primary,谁是 Standby。
- 同步流复制:主库提交事务时,必须等待备库接收日志。
2. 构建集群 StatefulSet
我们需要利用 StatefulSet 的序号特性:约定 -0 节点为主节点,其他为备节点。
在 statefulset.yaml 中添加 lifecycle 钩子和启动脚本:
yaml
3. 使用 Bitnami 风格 Chart
对于复杂的主备切换,建议使用成熟的 Helm Chart(如果存在)。我们可以通过 values-cluster.yaml 来配置:
yaml
部署命令:
bash
查看状态:
bash
第七部分:Python 连接验证(落地实战)
不管黑猫白猫,能连上的就是好数据库。我们将分别测试单机和集群的连接。
1. 环境准备
你需要安装 psycopg2-binary,这是 Python 连接 PostgreSQL/ openGauss 最通用的驱动。
bash
2. Python 连接代码
我们写一个 test_og.py,实现连接 -> 建表 -> 插入 -> 查询的全流程。
python
3. 运行测试
bash
预期输出:
text
第八部分:故障排查与避坑指南
在部署过程中,你可能会遇到以下几个“大坑”,这里提供解决方案:
- 密码策略失败
- 现象:Pod 不断重启,日志显示
password does not meet policy。 - 解决:openGauss 默认密码需要包含大写、小写、数字、特殊符号(如
@, #, $),长度至少 8 位。例如 MyPass@2024。
- ConfigMap 更新后不生效
- 现象:修改了 ConfigMap,但数据库参数没变。
- 解决:ConfigMap 是通过 Volume 挂载的,Pod 内通常不会热加载。需要手动重启 Pod:
kubectl rollout restart statefulset/my-og-opengauss -n database。
- 权限不足 (Permission Denied)
- 现象:日志显示无法写入
/var/lib/opengauss/data。 - 解决:openGauss 容器内默认使用
gaussdb 用户 (UID 1000)。确保你的 PV 或 HostPath 目录有写入权限,或者修改 SecurityContext。
- Python 连接报错
Authentication method 10 not supported- 现象:
psycopg2 报错。 - 解决:你的
pg_hba.conf 中 method 使用了 sha256,但 psycopg2 版本过旧,或者客户端缺少 SASL 认证。解决办法是降级 pg_hba.conf 中的加密方式为 md5,或者升级客户端驱动,并在 openGauss 配置中允许 MD5(虽然不推荐,但内网测试可用)。
- 集群模式下备库无法连接主库
- 现象:备库日志显示
could not connect to the primary server。 - 解决:检查
pg_hba.conf 是否允许 replication 连接。确保主备之间网络互通(Service Name 解析正确)。
总结
至此,我们已经完成了从零开始,利用 Helm 在 Kubernetes 上部署 openGauss 单机和集群的全过程。我们不仅使用了 StatefulSet 来管理数据库拓扑,还通过 ConfigMap 实现了配置与镜像的解耦,利用 NodePort 和 Ingress TCP 转发实现了外部访问,最后用 Python 脚本验证了数据的读写。
这种方案落地的意义在于:
- 基础设施即代码:通过 Helm values 文件,DBA 可以将复杂的数据库配置参数 Git 化管理。
- 快速交付:原本需要半天搭建的主备环境,现在只需
helm install 一分钟。 - 统一运维:结合 Prometheus 和 Operator,未来的数据库自治能力将完全基于 K8s 构建。
在云原生时代,数据库容器化已经不再是“洪水猛兽”,而是变成了提效增能的“倚天剑”。openGauss 作为一款高性能、高安全、高可靠的企业级开源关系型数据库,其与 Kubernetes 的结合是国产基础软件落地的重要一环。
很多朋友在本地玩 openGauss 都是用 Docker 或二进制,但在生产环境中,我们需要的是可自愈、易扩容、免运维的云原生数据库。
今天,我们就来一场实战。我将带你从零开始,使用 Kubernetes 生态的包管理神器 —— Helm,分别部署 openGauss 单机版 和 openGauss 集群版(主备) 。
在本文中,你将学到:
阅读前提:已安装 Kubernetes 集群 (1.19+)、Helm 3 客户端,并配置好 StorageClass。
第一部分:准备工作与 Helm Chart 结构设计
在动手敲命令之前,我们需要明白 Helm 是如何管理复杂应用的。一个标准的 openGauss Helm Chart 目录结构如下:
text
为什么选择 StatefulSet?
数据库是有状态的。
StatefulSet能为 Pod 提供稳定的网络标识(如opengauss-0)和稳定的持久化存储,这是Deployment无法做到的。第二部分:核心配置 —— ConfigMap 的妙用
在 openGauss 中,配置是灵魂。如果我们每次修改
postgresql.conf都要重新打包镜像,那就太“传统”了。在 K8s 中,我们使用 ConfigMap 将配置文件剥离出来。1. 配置 postgresql.conf
我们创建一个 ConfigMap 来存放主配置文件。这里特别注意 监听地址 和 连接数 的设置。
yaml
# templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ include "opengauss.fullname" . }}-config data: postgresql.conf: | # 监听所有 IP,允许集群内其他 Pod 访问 listen_addresses = '*' port = 5432 max_connections = 1000 # 内存配置 (根据 values.yaml 动态调整) shared_buffers = {{ .Values.resources.sharedBuffers }} log_directory = '/var/lib/opengauss/logs' # 集群模式必须开启的归档和复制参数 archive_mode = 'on' archive_command = 'cp %p /var/lib/opengauss/archive/%f' wal_level = 'logical' max_wal_senders = 10 max_replication_slots = 10 # 密码加密规则 password_encryption_type = 2 # 默认 SHA-2562. 配置 pg_hba.conf (访问控制)
如果不配置这个,你的 Python 代码会直接
Connection Refused。我们需要允许所有 Pod 网段访问,但强烈建议在生产环境中不要使用0.0.0.0/0,而是指定集群 CIDR。yaml
# templates/configmap.yaml (同一ConfigMap内的另一个数据项) pg_hba.conf: | # TYPE DATABASE USER ADDRESS METHOD # 本地连接信任 local all all trust # IPv4 本地连接 host all all 127.0.0.1/32 trust # Kubernetes Pod 网段访问(关键!) host all all 0.0.0.0/0 sha256 # 允许复制(主备同步) host replication replicator 0.0.0.0/0 sha2563. 挂载 ConfigMap
在
statefulset.yaml中,我们需要将 ConfigMap 里的文件挂载到容器内,覆盖默认配置。yaml
# templates/statefulset.yaml (片段) volumes: - name: opengauss-config configMap: name: {{ include "opengauss.fullname" . }}-config containers: - name: opengauss image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" volumeMounts: - name: opengauss-config mountPath: /opt/opengauss/data/postgresql.conf subPath: postgresql.conf - name: opengauss-config mountPath: /opt/opengauss/data/pg_hba.conf subPath: pg_hba.conf第三部分:网络暴露 —— ClusterIP 与 NodePort
在 K8s 内部,我们使用 ClusterIP 让其他微服务访问;如果需要外部(如你的本地电脑)连接,则需要 NodePort。
1. 内部服务 (ClusterIP)
这是默认的 Service,仅集群内部可见。
yaml
# templates/svc.yaml apiVersion: v1 kind: Service metadata: name: {{ include "opengauss.fullname" . }}-headless spec: clusterIP: None # Headless Service 用于 StatefulSet 网络标识 ports: - name: tcp-sql port: 5432 targetPort: 5432 selector: app: {{ include "opengauss.name" . }} --- apiVersion: v1 kind: Service metadata: name: {{ include "opengauss.fullname" . }}-clusterip spec: type: ClusterIP ports: - port: 5432 selector: app: {{ include "opengauss.name" . }}2. 外部访问 (NodePort)
如果你是在云上,通常会搭配云厂商的 LoadBalancer。但在本地或私有云,NodePort 是最简单的暴露方式。
yaml
# templates/svc-nodeport.yaml (可选,根据 values 开关) {{- if .Values.service.nodePort.enabled }} apiVersion: v1 kind: Service metadata: name: {{ include "opengauss.fullname" . }}-nodeport spec: type: NodePort ports: - port: 5432 nodePort: {{ .Values.service.nodePort.port }} # 范围 30000-32767 selector: app: {{ include "opengauss.name" . }} {{- end }}第四部分:进阶暴露 —— Ingress 的 TCP 配置
通常 Ingress 处理 HTTP(S) 流量,但
nginx-ingress-controller支持通过 ConfigMap 代理 TCP/UDP 流量。这对于想要通过域名(如opengauss.internal.example.com)访问数据库非常有用。实现步骤:
nginx-ingress-controller的 ConfigMap,开放新端口。注意:这需要集群管理员修改 Ingress Controller 的部署,如果只是普通用户,建议直接用 NodePort。
如果你是全栈管理员,可以这样配置 Ingress Controller 的 ConfigMap:
yaml
第五部分:部署 openGauss 单机版
一切就绪,开始实战。假设你已经写好了上述的 Chart,或者使用社区 Chart。
1. 创建 values.yaml
定制我们的单机版参数。
yaml
# values-single.yaml global: storageClass: "local-path" # 你的存储类 image: repository: opengauss tag: 3.0.0 pullPolicy: IfNotPresent auth: username: "gaussdb" password: "OpenGauss@123" # 必须符合复杂度要求 database: "appdb" replicaCount: 1 # 单机模式 resources: requests: memory: "2Gi" cpu: "1000m" sharedBuffers: "512MB" service: type: ClusterIP nodePort: enabled: true port: 304322. 执行安装
bash
3. 验证
bash
第六部分:部署 openGauss 集群版(主备)
集群版是 openGauss 的高可用形态,通常是一主一备或多备。Helm 可以通过脚本和启动探针自动配置主备关系。
1. 集群配置难点
2. 构建集群 StatefulSet
我们需要利用 StatefulSet 的序号特性:约定
-0节点为主节点,其他为备节点。在
statefulset.yaml中添加lifecycle钩子和启动脚本:yaml
# templates/statefulset.yaml 环境变量部分 env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: REPLICATE_FROM value: "{{ .Values.primaryNode }}" # 例如 my-og-opengauss-0 - name: IS_PRIMARY value: "{{ if eq (list .Release.Name .Values.role) }}true{{ end }}"3. 使用 Bitnami 风格 Chart
对于复杂的主备切换,建议使用成熟的 Helm Chart(如果存在)。我们可以通过
values-cluster.yaml来配置:yaml
# values-cluster.yaml replicaCount: 2 # 1主1备 primary: persistence: size: 20Gi service: type: ClusterIP secondary: replicaCount: 1 persistence: size: 20Gi service: type: ClusterIP syncReplication: true # 开启强同步部署命令:
bash
查看状态:
bash
第七部分:Python 连接验证(落地实战)
不管黑猫白猫,能连上的就是好数据库。我们将分别测试单机和集群的连接。
1. 环境准备
你需要安装
psycopg2-binary,这是 Python 连接 PostgreSQL/ openGauss 最通用的驱动。bash
2. Python 连接代码
我们写一个
test_og.py,实现连接 -> 建表 -> 插入 -> 查询的全流程。python
import psycopg2 import sys def test_connection(host, port, user, password, database, is_cluster=False): """ 测试 openGauss 连接 """ conn = None try: # 连接数据库 # 注意:openGauss 默认兼容 PostgreSQL 协议 conn = psycopg2.connect( host=host, port=port, user=user, password=password, database=database, connect_timeout=10 ) conn.autocommit = False cur = conn.cursor() # 1. 验证数据库版本 cur.execute("SELECT version();") version = cur.fetchone() print(f"[✓] 连接成功! 数据库版本: {version[0].split(',')[0]}") # 2. 创建测试表 (验证写权限) print("[*] 正在创建测试表...") cur.execute(""" CREATE TABLE IF NOT EXISTS k8s_test ( id SERIAL PRIMARY KEY, message TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); """) conn.commit() print("[✓] 建表成功") # 3. 插入数据 print("[*] 正在插入数据...") cur.execute("INSERT INTO k8s_test (message) VALUES (%s) RETURNING id;", ("Hello from K8s Helm",)) inserted_id = cur.fetchone()[0] conn.commit() print(f"[✓] 插入成功,记录 ID: {inserted_id}") # 4. 查询数据 print("[*] 正在查询数据...") cur.execute("SELECT id, message, created_at FROM k8s_test WHERE id = %s;", (inserted_id,)) row = cur.fetchone() print(f"[✓] 查询结果: ID={row[0]}, Msg={row[1]}, Time={row[2]}") # 5. 如果是集群模式,额外检查节点信息(可选) if is_cluster: cur.execute("SELECT node_name, node_type FROM pgxc_node;") nodes = cur.fetchall() print(f"[✓] 集群节点信息: {nodes}") cur.close() return True except Exception as e: print(f"[✗] 发生错误: {e}") return False finally: if conn: conn.close() if __name__ == "__main__": # ================= 单机测试 ================= print("\n" + "="*30) print("测试 1: 连接单机 openGauss (NodePort)") print("="*30) # 这里填入你 K8s 集群任意节点的 IP,和 NodePort 端口 (30432) single_host = "192.168.1.100" # 你的 K8s Node IP single_port = 30432 test_connection( host=single_host, port=single_port, user="gaussdb", password="OpenGauss@123", database="appdb", is_cluster=False ) # ================= 集群测试 ================= print("\n" + "="*30) print("测试 2: 连接集群 openGauss (ClusterIP via Port Forward)") print("="*30) print("提示: 如果测试集群,请先运行以下命令进行端口转发:") print("kubectl port-forward -n database service/my-og-cluster-opengauss-clusterip 5432:5432") print("然后按 Enter 继续...") input() test_connection( host="127.0.0.1", port=5432, user="gaussdb", password="OpenGauss@123", database="appdb", is_cluster=True )3. 运行测试
bash
预期输出:
text
第八部分:故障排查与避坑指南
在部署过程中,你可能会遇到以下几个“大坑”,这里提供解决方案:
password does not meet policy。@,#,$),长度至少 8 位。例如MyPass@2024。kubectl rollout restart statefulset/my-og-opengauss -n database。/var/lib/opengauss/data。gaussdb用户 (UID 1000)。确保你的 PV 或 HostPath 目录有写入权限,或者修改 SecurityContext。Authentication method 10 not supportedpsycopg2报错。pg_hba.conf中 method 使用了sha256,但psycopg2版本过旧,或者客户端缺少 SASL 认证。解决办法是降级pg_hba.conf中的加密方式为md5,或者升级客户端驱动,并在 openGauss 配置中允许 MD5(虽然不推荐,但内网测试可用)。could not connect to the primary server。pg_hba.conf是否允许replication连接。确保主备之间网络互通(Service Name 解析正确)。总结
至此,我们已经完成了从零开始,利用 Helm 在 Kubernetes 上部署 openGauss 单机和集群的全过程。我们不仅使用了 StatefulSet 来管理数据库拓扑,还通过 ConfigMap 实现了配置与镜像的解耦,利用 NodePort 和 Ingress TCP 转发实现了外部访问,最后用 Python 脚本验证了数据的读写。
这种方案落地的意义在于:
helm install一分钟。