From 0bc53c378ee01db26bebd90137a52b01aa7b3c21 Mon Sep 17 00:00:00 2001 From: Jinpei Su Date: Thu, 18 Jun 2026 06:01:39 +0000 Subject: [PATCH 1/3] add PostgreSQL node migration and CloudBeaver solutions (MIDDLEWARE-31526) Precipitate historical internal KB PostgreSQL solutions, modernized to the current acid.zalan.do/v1 postgresql CR and verified live on ACP 4.2/4.3, bilingual (en + zh): - KB260515007 How to Migrate a PostgreSQL Instance to Another Node - KB260515008 How to Deploy CloudBeaver for PostgreSQL Management Co-Authored-By: Claude Opus 4.8 (1M context) --- ...y_CloudBeaver_for_PostgreSQL_Management.md | 159 +++++++++++++++++ ...e_a_PostgreSQL_Instance_to_Another_Node.md | 130 ++++++++++++++ ...y_CloudBeaver_for_PostgreSQL_Management.md | 160 ++++++++++++++++++ ...e_a_PostgreSQL_Instance_to_Another_Node.md | 105 ++++++++++++ 4 files changed, 554 insertions(+) create mode 100644 docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md create mode 100644 docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md create mode 100644 docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md create mode 100644 docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md diff --git a/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md b/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md new file mode 100644 index 00000000..4cd63077 --- /dev/null +++ b/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md @@ -0,0 +1,159 @@ +--- +kind: + - How To +products: + - Alauda Application Services +ProductsVersion: + - 4.0,4.1,4.2,4.3 +id: KB260515008 +--- + +# How to Deploy CloudBeaver for PostgreSQL Management + +## Issue + +You need a web-based SQL client for browsing and querying PostgreSQL instances managed by Alauda Application Services, without installing a desktop tool on every operator's workstation. CloudBeaver is the open-source web edition of DBeaver and runs as a single-pod Deployment on Kubernetes. This how-to deploys CloudBeaver and connects it to a PostgreSQL cluster managed by the PostgreSQL Operator. + +## Environment + +- Any Kubernetes cluster reachable to operators (NodePort exposure is used below; Ingress / Route works equally well) +- A `StorageClass` capable of provisioning ReadWriteOnce PVCs — used to persist CloudBeaver workspace state across pod restarts +- Network reachability from the CloudBeaver pod to the target PostgreSQL Service (`` on port 5432) + +## Resolution + +### 1. Prepare the manifest + +Save the following to `cloudbeaver.yaml`. Adjust `storageClassName`, image registry, and resource requests to match your environment: + +```yaml +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cloudbeaver +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: sc-topolvm # replace with any RWO StorageClass available in the cluster + volumeMode: Filesystem +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cloudbeaver +spec: + replicas: 1 + selector: + matchLabels: + app: cloudbeaver + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + template: + metadata: + labels: + app: cloudbeaver + spec: + containers: + - name: cloudbeaver + image: docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest + imagePullPolicy: Always + ports: + - name: web + containerPort: 8978 + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumeMounts: + - name: cloudbeaver-data + mountPath: /opt/cloudbeaver/workspace + volumes: + - name: cloudbeaver-data + persistentVolumeClaim: + claimName: cloudbeaver +--- +apiVersion: v1 +kind: Service +metadata: + name: cloudbeaver +spec: + type: NodePort + selector: + app: cloudbeaver + ports: + - name: web + port: 8978 + targetPort: 8978 + protocol: TCP +``` + +> CloudBeaver stores its administrator password, saved connections, and query history under `/opt/cloudbeaver/workspace`. Without a persistent volume, everything is lost on every pod restart. Confirm the chosen `storageClassName` exists in the target cluster before applying. + +> **Air-gapped / IPv6-only clusters:** the public `docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest` image may be unreachable from the cluster. Mirror it into the cluster's own registry first and reference that path in the Deployment, for example `skopeo copy docker://docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest docker:///dbeaver/cloudbeaver:latest`. + +### 2. Deploy + +```bash +kubectl -n apply -f cloudbeaver.yaml +kubectl -n rollout status deploy/cloudbeaver +``` + +### 3. Discover the access URL + +The Service uses NodePort, so any node IP plus the allocated NodePort exposes the UI: + +```bash +namespace= +HOST=$(kubectl -n "$namespace" get pod -l app=cloudbeaver \ + -o jsonpath='{.items[0].status.hostIP}') +PORT=$(kubectl -n "$namespace" get svc cloudbeaver \ + -o jsonpath='{.spec.ports[0].nodePort}') +echo "http://$HOST:$PORT" +``` + +Open the URL in a browser. + +### 4. Initial setup + +1. On first launch CloudBeaver prompts you to set the administrator password. Choose a strong password and store it safely — this account governs all subsequent server-side configuration. +2. Log in with the administrator user. +3. (Optional) Switch the UI language under the user menu in the top-right. + +### 5. Connect to a PostgreSQL instance + +1. Click **New Connection** and choose **PostgreSQL**. +2. Fill **Host** with the cluster Service name and **Port** `5432`. From inside the cluster the host is `.` (the read-write Service); the `-repl` Service points at replicas. From outside the cluster, retrieve the NodePort or LoadBalancer address: + + ```bash + kubectl -n get svc + ``` + +3. Enter the database user and password. The `postgres` superuser password is available in the cluster as an environment variable / Secret: + + ```bash + kubectl exec -n -0 -c postgres -- \ + bash -c 'echo $PGPASSWORD_SUPERUSER' + ``` + +4. (Optional) Set **Database** to the target database; otherwise CloudBeaver connects to the default `postgres` database. +5. Under **Access Management**, grant the current CloudBeaver user permission to use the new connection. +6. Save and test the connection. SQL editors can now be opened from the browser and queries executed against the PostgreSQL cluster. + +### 6. Uninstall + +```bash +kubectl -n delete -f cloudbeaver.yaml +``` + +The PVC is removed alongside the rest of the manifest. To preserve CloudBeaver state for a future redeploy, delete only the Deployment and Service and re-attach the existing PVC during the next install. diff --git a/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md b/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md new file mode 100644 index 00000000..b82b457b --- /dev/null +++ b/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md @@ -0,0 +1,130 @@ +--- +kind: + - Solution +products: + - Alauda Application Services +ProductsVersion: + - 4.0,4.1,4.2,4.3 +id: KB260515007 +--- + +# How to Migrate a PostgreSQL Instance to Another Node + +## Issue + +A PostgreSQL cluster managed by the PostgreSQL Operator uses node-local storage +(for example TopoLVM). One or more instances must be moved off their current +node — because the node is being decommissioned, or an instance must run on a +specific compute node. Because the data lives in a node-local PersistentVolume, +the pod cannot simply be rescheduled; the volume is pinned to its node. + +## Environment + +- Alauda Application Services PostgreSQL Operator (Zalando-based, + `acid.zalan.do/v1` `postgresql` resource). +- Node-local storage such as TopoLVM (each PVC is bound to one node). +- At least one target node with enough free capacity. Because migration + re-clones data, the target node should have capacity for roughly **twice** the + instance's PVC size during the transition. + +## Resolution + +The migration relies on a property of the Operator: when an instance's PVC and +pod are deleted, the StatefulSet recreates the pod, a fresh PVC is provisioned +wherever the pod is scheduled, and Patroni re-clones the data from the current +leader. Data is preserved through streaming replication, not by moving the +volume. + +> Validated on ACP 4.2 and 4.3: after deleting a replica's PVC and pod, the +> member was recreated on a node, re-synced from the leader, and previously +> written rows were present on the resynced member. + +In the examples below set `$NAMESPACE` and `$CLUSTER_NAME` for the target +cluster. Replace placeholder node names with your own. + +### 1. Confirm the current placement + +```bash +kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME +kubectl get pvc -n $NAMESPACE -o wide | grep $CLUSTER_NAME +``` + +Note which member is the leader (do not delete the leader's volume first): + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list +``` + +### 2. Restrict scheduling to the target node(s) + +So the recreated pod lands only on a desired node, cordon the other eligible +nodes (or use a `nodeSelector`/label that only the target nodes carry). Keep at +least the target node schedulable. + +```bash +# Example: label the source and target nodes, then select them +kubectl label node target=true --overwrite +``` + +If you use a label-based selector, set it on the instance: + +```bash +kubectl patch postgresql -n $NAMESPACE $CLUSTER_NAME --type merge \ + -p '{"spec":{"nodeSelector":{"target":"true"}}}' +``` + +### 3. Migrate one member at a time + +Always migrate a **non-leader** member first. Delete its PVC and pod together — +the PVC deletion blocks until the pod that mounts it is gone, so delete the pod +in parallel: + +```bash +# Delete the data PVC (it will stay in Terminating until the pod is gone) +kubectl delete pvc pgdata-$CLUSTER_NAME-1 -n $NAMESPACE --wait=false + +# Delete the pod to release the PVC +kubectl delete pod $CLUSTER_NAME-1 -n $NAMESPACE +``` + +The StatefulSet recreates `$CLUSTER_NAME-1`; a new PVC is provisioned on the +scheduled node and Patroni re-clones from the leader. + +### 4. Verify the member rejoined with its data + +```bash +kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME-1 +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list +``` + +The migrated member should return to role `Replica`, state `running`/`streaming` +with `Lag in MB` `0`. Spot-check data on the member (it is read-only / in +recovery): + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-1 -c postgres -- \ + psql -U postgres -tAc "SELECT pg_is_in_recovery();" # expect t +``` + +### 5. Migrate the (former) leader if required + +To move the leader, first perform a switchover so another member becomes leader, +then repeat steps 3–4 for the old leader: + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- \ + patronictl switchover $CLUSTER_NAME --force +``` + +### 6. Restore scheduling + +Uncordon any nodes you cordoned and remove temporary labels/`nodeSelector` once +all members are on their intended nodes. + +## Notes + +- Migrate members one at a time and wait for each to fully re-sync (`Lag = 0`) + before moving the next, so the cluster always retains a healthy quorum. +- For a single-instance cluster, temporarily scale to two instances, let the new + member sync on the target node, switch over, then scale back to one — this + avoids downtime that a delete-and-reclone of the sole instance would cause. diff --git a/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md b/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md new file mode 100644 index 00000000..06360ae8 --- /dev/null +++ b/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md @@ -0,0 +1,160 @@ +--- +kind: + - How To +products: + - Alauda Application Services +ProductsVersion: + - '4.0,4.1,4.2,4.3' +id: KB260515008 +sourceSHA: e84115331a26da1f333d7e670c2f23f9970f7e06f98f168db22f6b0646ca7e5c +--- + +# 如何部署 CloudBeaver 以管理 PostgreSQL + +## 问题 + +你需要一个基于 Web 的 SQL 客户端,用于浏览和查询由 Alauda Application Services 管理的 PostgreSQL 实例,而无需在每位运维人员的工作站上安装桌面工具。CloudBeaver 是 DBeaver 的开源 Web 版本,作为单 Pod 的 Deployment 运行在 Kubernetes 上。本文档部署 CloudBeaver 并将其连接到由 PostgreSQL Operator 管理的 PostgreSQL 集群。 + +## 环境 + +- 任意运维人员可访问的 Kubernetes 集群(下文使用 NodePort 暴露;Ingress / Route 同样适用) +- 能够供给 ReadWriteOnce PVC 的 `StorageClass`——用于在 Pod 重启间持久化 CloudBeaver 工作区状态 +- 从 CloudBeaver Pod 到目标 PostgreSQL Service(`` 的 5432 端口)的网络可达性 + +## 解决方案 + +### 1. 准备清单 + +将以下内容保存为 `cloudbeaver.yaml`。根据环境调整 `storageClassName`、镜像仓库与资源请求: + +```yaml +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cloudbeaver +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: sc-topolvm # 替换为集群中任意可用的 RWO StorageClass + volumeMode: Filesystem +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cloudbeaver +spec: + replicas: 1 + selector: + matchLabels: + app: cloudbeaver + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + template: + metadata: + labels: + app: cloudbeaver + spec: + containers: + - name: cloudbeaver + image: docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest + imagePullPolicy: Always + ports: + - name: web + containerPort: 8978 + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumeMounts: + - name: cloudbeaver-data + mountPath: /opt/cloudbeaver/workspace + volumes: + - name: cloudbeaver-data + persistentVolumeClaim: + claimName: cloudbeaver +--- +apiVersion: v1 +kind: Service +metadata: + name: cloudbeaver +spec: + type: NodePort + selector: + app: cloudbeaver + ports: + - name: web + port: 8978 + targetPort: 8978 + protocol: TCP +``` + +> CloudBeaver 将其管理员密码、已保存的连接和查询历史存储在 `/opt/cloudbeaver/workspace` 下。没有持久卷,所有内容都会在每次 Pod 重启时丢失。应用前请确认所选 `storageClassName` 在目标集群中存在。 + +> **隔离网络 / 仅 IPv6 集群:** 公共镜像 `docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest` 可能从集群内无法访问。请先将其镜像到集群自身的仓库,并在 Deployment 中引用该路径,例如 `skopeo copy docker://docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest docker:///dbeaver/cloudbeaver:latest`。 + +### 2. 部署 + +```bash +kubectl -n apply -f cloudbeaver.yaml +kubectl -n rollout status deploy/cloudbeaver +``` + +### 3. 获取访问地址 + +Service 使用 NodePort,因此任意节点 IP 加上分配的 NodePort 即可访问 UI: + +```bash +namespace= +HOST=$(kubectl -n "$namespace" get pod -l app=cloudbeaver \ + -o jsonpath='{.items[0].status.hostIP}') +PORT=$(kubectl -n "$namespace" get svc cloudbeaver \ + -o jsonpath='{.spec.ports[0].nodePort}') +echo "http://$HOST:$PORT" +``` + +在浏览器中打开该地址。 + +### 4. 初始设置 + +1. 首次启动时,CloudBeaver 会提示设置管理员密码。请选择强密码并妥善保存——该账户管理后续所有服务端配置。 +2. 使用管理员用户登录。 +3. (可选)在右上角用户菜单中切换 UI 语言。 + +### 5. 连接 PostgreSQL 实例 + +1. 点击 **New Connection** 并选择 **PostgreSQL**。 +2. **Host** 填写集群 Service 名称,**Port** 填写 `5432`。集群内部主机为 `.`(读写 Service);`-repl` Service 指向副本。从集群外部访问时,获取 NodePort 或 LoadBalancer 地址: + + ```bash + kubectl -n get svc + ``` + +3. 输入数据库用户与密码。`postgres` 超级用户密码以环境变量 / Secret 形式存在于集群中: + + ```bash + kubectl exec -n -0 -c postgres -- \ + bash -c 'echo $PGPASSWORD_SUPERUSER' + ``` + +4. (可选)将 **Database** 设置为目标数据库;否则 CloudBeaver 连接到默认的 `postgres` 数据库。 +5. 在 **Access Management** 中,授予当前 CloudBeaver 用户使用该新连接的权限。 +6. 保存并测试连接。此后即可从浏览器打开 SQL 编辑器并对 PostgreSQL 集群执行查询。 + +### 6. 卸载 + +```bash +kubectl -n delete -f cloudbeaver.yaml +``` + +PVC 会随清单的其余部分一并删除。若要为将来重新部署保留 CloudBeaver 状态,仅删除 Deployment 与 Service,并在下次安装时重新挂载现有 PVC。 diff --git a/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md b/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md new file mode 100644 index 00000000..bcf155e8 --- /dev/null +++ b/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md @@ -0,0 +1,105 @@ +--- +kind: + - Solution +products: + - Alauda Application Services +ProductsVersion: + - '4.0,4.1,4.2,4.3' +id: KB260515007 +sourceSHA: 68545d5287dbfbc24261231c54b484401a71c97c16407e79865eea4f4aefd110 +--- + +# 如何将 PostgreSQL 实例迁移到其他节点 + +## 问题 + +由 PostgreSQL Operator 管理的 PostgreSQL 集群使用节点本地存储(例如 TopoLVM)。由于节点下线,或某个实例需要运行在指定的计算节点上,需要将一个或多个实例迁出当前节点。由于数据位于节点本地的 PersistentVolume 上,Pod 无法被直接重新调度——卷被固定在其所在节点上。 + +## 环境 + +- Alauda Application Services PostgreSQL Operator(基于 Zalando,`acid.zalan.do/v1` 的 `postgresql` 资源)。 +- 节点本地存储,例如 TopoLVM(每个 PVC 绑定到单个节点)。 +- 至少一个有足够空闲容量的目标节点。由于迁移会重新克隆数据,目标节点在迁移期间应具备约为实例 PVC 大小**两倍**的容量。 + +## 解决方案 + +迁移依赖 Operator 的一个特性:当某个实例的 PVC 与 Pod 被删除后,StatefulSet 会重建该 Pod,在 Pod 被调度到的节点上重新供给一个新的 PVC,Patroni 则从当前 Leader 重新克隆数据。数据通过流复制得以保留,而非通过移动卷。 + +> 已在 ACP 4.2 与 4.3 上验证:删除某副本的 PVC 与 Pod 后,该成员在节点上被重建,从 Leader 重新同步,先前写入的数据行在重新同步后的成员上依然存在。 + +以下示例中,请为目标集群设置 `$NAMESPACE` 与 `$CLUSTER_NAME`,并将占位节点名替换为实际节点名。 + +### 1. 确认当前分布 + +```bash +kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME +kubectl get pvc -n $NAMESPACE -o wide | grep $CLUSTER_NAME +``` + +确认哪个成员是 Leader(不要先删除 Leader 的卷): + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list +``` + +### 2. 将调度限制到目标节点 + +为使重建的 Pod 只落在期望的节点上,将其他可调度节点设置为不可调度(cordon),或使用仅目标节点具备的 `nodeSelector`/标签,并至少保留目标节点可调度。 + +```bash +# 示例:为源节点与目标节点打标签,然后基于标签选择 +kubectl label node target=true --overwrite +``` + +如使用基于标签的选择器,在实例上设置: + +```bash +kubectl patch postgresql -n $NAMESPACE $CLUSTER_NAME --type merge \ + -p '{"spec":{"nodeSelector":{"target":"true"}}}' +``` + +### 3. 逐个迁移成员 + +务必先迁移**非 Leader** 成员。同时删除其 PVC 与 Pod——PVC 的删除会阻塞,直到挂载它的 Pod 消失,因此需并行删除 Pod: + +```bash +# 删除数据 PVC(在 Pod 消失前会一直处于 Terminating) +kubectl delete pvc pgdata-$CLUSTER_NAME-1 -n $NAMESPACE --wait=false + +# 删除 Pod 以释放 PVC +kubectl delete pod $CLUSTER_NAME-1 -n $NAMESPACE +``` + +StatefulSet 会重建 `$CLUSTER_NAME-1`;在被调度的节点上供给新的 PVC,Patroni 从 Leader 重新克隆。 + +### 4. 验证成员已带数据重新加入 + +```bash +kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME-1 +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list +``` + +迁移后的成员应恢复为 `Replica` 角色,状态 `running`/`streaming`,`Lag in MB` 为 `0`。在该成员上抽查数据(它是只读 / 处于恢复状态): + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-1 -c postgres -- \ + psql -U postgres -tAc "SELECT pg_is_in_recovery();" # 期望为 t +``` + +### 5. 如需迁移(原)Leader + +要迁移 Leader,先执行切换(switchover)让其他成员成为 Leader,然后对原 Leader 重复第 3–4 步: + +```bash +kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- \ + patronictl switchover $CLUSTER_NAME --force +``` + +### 6. 恢复调度 + +待所有成员都位于期望节点后,取消对任何节点的 cordon,并移除临时标签/`nodeSelector`。 + +## 说明 + +- 逐个迁移成员,并在迁移下一个之前等待每个成员完全重新同步(`Lag = 0`),以使集群始终保持健康的法定数量。 +- 对于单实例集群,临时扩容到两个实例,让新成员在目标节点上完成同步,执行切换后再缩容回一个实例——以避免对唯一实例执行删除并重新克隆所导致的停机。 From 73e1b5d6dd08f355c0702c90b8845e3044ab094c Mon Sep 17 00:00:00 2001 From: Jinpei Su Date: Thu, 18 Jun 2026 07:16:34 +0000 Subject: [PATCH 2/3] docs: drop hand-written zh mirrors (pipeline auto-generates them) The zh translations are produced by the translation pipeline from the en sources (tracked via sourceSHA); they should not be committed by hand. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...y_CloudBeaver_for_PostgreSQL_Management.md | 160 ------------------ ...e_a_PostgreSQL_Instance_to_Another_Node.md | 105 ------------ 2 files changed, 265 deletions(-) delete mode 100644 docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md delete mode 100644 docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md diff --git a/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md b/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md deleted file mode 100644 index 06360ae8..00000000 --- a/docs/zh/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -kind: - - How To -products: - - Alauda Application Services -ProductsVersion: - - '4.0,4.1,4.2,4.3' -id: KB260515008 -sourceSHA: e84115331a26da1f333d7e670c2f23f9970f7e06f98f168db22f6b0646ca7e5c ---- - -# 如何部署 CloudBeaver 以管理 PostgreSQL - -## 问题 - -你需要一个基于 Web 的 SQL 客户端,用于浏览和查询由 Alauda Application Services 管理的 PostgreSQL 实例,而无需在每位运维人员的工作站上安装桌面工具。CloudBeaver 是 DBeaver 的开源 Web 版本,作为单 Pod 的 Deployment 运行在 Kubernetes 上。本文档部署 CloudBeaver 并将其连接到由 PostgreSQL Operator 管理的 PostgreSQL 集群。 - -## 环境 - -- 任意运维人员可访问的 Kubernetes 集群(下文使用 NodePort 暴露;Ingress / Route 同样适用) -- 能够供给 ReadWriteOnce PVC 的 `StorageClass`——用于在 Pod 重启间持久化 CloudBeaver 工作区状态 -- 从 CloudBeaver Pod 到目标 PostgreSQL Service(`` 的 5432 端口)的网络可达性 - -## 解决方案 - -### 1. 准备清单 - -将以下内容保存为 `cloudbeaver.yaml`。根据环境调整 `storageClassName`、镜像仓库与资源请求: - -```yaml ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: cloudbeaver -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - storageClassName: sc-topolvm # 替换为集群中任意可用的 RWO StorageClass - volumeMode: Filesystem ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cloudbeaver -spec: - replicas: 1 - selector: - matchLabels: - app: cloudbeaver - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - template: - metadata: - labels: - app: cloudbeaver - spec: - containers: - - name: cloudbeaver - image: docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest - imagePullPolicy: Always - ports: - - name: web - containerPort: 8978 - protocol: TCP - resources: - limits: - cpu: "1" - memory: 1Gi - requests: - cpu: 100m - memory: 256Mi - volumeMounts: - - name: cloudbeaver-data - mountPath: /opt/cloudbeaver/workspace - volumes: - - name: cloudbeaver-data - persistentVolumeClaim: - claimName: cloudbeaver ---- -apiVersion: v1 -kind: Service -metadata: - name: cloudbeaver -spec: - type: NodePort - selector: - app: cloudbeaver - ports: - - name: web - port: 8978 - targetPort: 8978 - protocol: TCP -``` - -> CloudBeaver 将其管理员密码、已保存的连接和查询历史存储在 `/opt/cloudbeaver/workspace` 下。没有持久卷,所有内容都会在每次 Pod 重启时丢失。应用前请确认所选 `storageClassName` 在目标集群中存在。 - -> **隔离网络 / 仅 IPv6 集群:** 公共镜像 `docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest` 可能从集群内无法访问。请先将其镜像到集群自身的仓库,并在 Deployment 中引用该路径,例如 `skopeo copy docker://docker-mirrors.alauda.cn/dbeaver/cloudbeaver:latest docker:///dbeaver/cloudbeaver:latest`。 - -### 2. 部署 - -```bash -kubectl -n apply -f cloudbeaver.yaml -kubectl -n rollout status deploy/cloudbeaver -``` - -### 3. 获取访问地址 - -Service 使用 NodePort,因此任意节点 IP 加上分配的 NodePort 即可访问 UI: - -```bash -namespace= -HOST=$(kubectl -n "$namespace" get pod -l app=cloudbeaver \ - -o jsonpath='{.items[0].status.hostIP}') -PORT=$(kubectl -n "$namespace" get svc cloudbeaver \ - -o jsonpath='{.spec.ports[0].nodePort}') -echo "http://$HOST:$PORT" -``` - -在浏览器中打开该地址。 - -### 4. 初始设置 - -1. 首次启动时,CloudBeaver 会提示设置管理员密码。请选择强密码并妥善保存——该账户管理后续所有服务端配置。 -2. 使用管理员用户登录。 -3. (可选)在右上角用户菜单中切换 UI 语言。 - -### 5. 连接 PostgreSQL 实例 - -1. 点击 **New Connection** 并选择 **PostgreSQL**。 -2. **Host** 填写集群 Service 名称,**Port** 填写 `5432`。集群内部主机为 `.`(读写 Service);`-repl` Service 指向副本。从集群外部访问时,获取 NodePort 或 LoadBalancer 地址: - - ```bash - kubectl -n get svc - ``` - -3. 输入数据库用户与密码。`postgres` 超级用户密码以环境变量 / Secret 形式存在于集群中: - - ```bash - kubectl exec -n -0 -c postgres -- \ - bash -c 'echo $PGPASSWORD_SUPERUSER' - ``` - -4. (可选)将 **Database** 设置为目标数据库;否则 CloudBeaver 连接到默认的 `postgres` 数据库。 -5. 在 **Access Management** 中,授予当前 CloudBeaver 用户使用该新连接的权限。 -6. 保存并测试连接。此后即可从浏览器打开 SQL 编辑器并对 PostgreSQL 集群执行查询。 - -### 6. 卸载 - -```bash -kubectl -n delete -f cloudbeaver.yaml -``` - -PVC 会随清单的其余部分一并删除。若要为将来重新部署保留 CloudBeaver 状态,仅删除 Deployment 与 Service,并在下次安装时重新挂载现有 PVC。 diff --git a/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md b/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md deleted file mode 100644 index bcf155e8..00000000 --- a/docs/zh/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -kind: - - Solution -products: - - Alauda Application Services -ProductsVersion: - - '4.0,4.1,4.2,4.3' -id: KB260515007 -sourceSHA: 68545d5287dbfbc24261231c54b484401a71c97c16407e79865eea4f4aefd110 ---- - -# 如何将 PostgreSQL 实例迁移到其他节点 - -## 问题 - -由 PostgreSQL Operator 管理的 PostgreSQL 集群使用节点本地存储(例如 TopoLVM)。由于节点下线,或某个实例需要运行在指定的计算节点上,需要将一个或多个实例迁出当前节点。由于数据位于节点本地的 PersistentVolume 上,Pod 无法被直接重新调度——卷被固定在其所在节点上。 - -## 环境 - -- Alauda Application Services PostgreSQL Operator(基于 Zalando,`acid.zalan.do/v1` 的 `postgresql` 资源)。 -- 节点本地存储,例如 TopoLVM(每个 PVC 绑定到单个节点)。 -- 至少一个有足够空闲容量的目标节点。由于迁移会重新克隆数据,目标节点在迁移期间应具备约为实例 PVC 大小**两倍**的容量。 - -## 解决方案 - -迁移依赖 Operator 的一个特性:当某个实例的 PVC 与 Pod 被删除后,StatefulSet 会重建该 Pod,在 Pod 被调度到的节点上重新供给一个新的 PVC,Patroni 则从当前 Leader 重新克隆数据。数据通过流复制得以保留,而非通过移动卷。 - -> 已在 ACP 4.2 与 4.3 上验证:删除某副本的 PVC 与 Pod 后,该成员在节点上被重建,从 Leader 重新同步,先前写入的数据行在重新同步后的成员上依然存在。 - -以下示例中,请为目标集群设置 `$NAMESPACE` 与 `$CLUSTER_NAME`,并将占位节点名替换为实际节点名。 - -### 1. 确认当前分布 - -```bash -kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME -kubectl get pvc -n $NAMESPACE -o wide | grep $CLUSTER_NAME -``` - -确认哪个成员是 Leader(不要先删除 Leader 的卷): - -```bash -kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list -``` - -### 2. 将调度限制到目标节点 - -为使重建的 Pod 只落在期望的节点上,将其他可调度节点设置为不可调度(cordon),或使用仅目标节点具备的 `nodeSelector`/标签,并至少保留目标节点可调度。 - -```bash -# 示例:为源节点与目标节点打标签,然后基于标签选择 -kubectl label node target=true --overwrite -``` - -如使用基于标签的选择器,在实例上设置: - -```bash -kubectl patch postgresql -n $NAMESPACE $CLUSTER_NAME --type merge \ - -p '{"spec":{"nodeSelector":{"target":"true"}}}' -``` - -### 3. 逐个迁移成员 - -务必先迁移**非 Leader** 成员。同时删除其 PVC 与 Pod——PVC 的删除会阻塞,直到挂载它的 Pod 消失,因此需并行删除 Pod: - -```bash -# 删除数据 PVC(在 Pod 消失前会一直处于 Terminating) -kubectl delete pvc pgdata-$CLUSTER_NAME-1 -n $NAMESPACE --wait=false - -# 删除 Pod 以释放 PVC -kubectl delete pod $CLUSTER_NAME-1 -n $NAMESPACE -``` - -StatefulSet 会重建 `$CLUSTER_NAME-1`;在被调度的节点上供给新的 PVC,Patroni 从 Leader 重新克隆。 - -### 4. 验证成员已带数据重新加入 - -```bash -kubectl get pod -n $NAMESPACE -o wide | grep $CLUSTER_NAME-1 -kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- patronictl list -``` - -迁移后的成员应恢复为 `Replica` 角色,状态 `running`/`streaming`,`Lag in MB` 为 `0`。在该成员上抽查数据(它是只读 / 处于恢复状态): - -```bash -kubectl exec -n $NAMESPACE $CLUSTER_NAME-1 -c postgres -- \ - psql -U postgres -tAc "SELECT pg_is_in_recovery();" # 期望为 t -``` - -### 5. 如需迁移(原)Leader - -要迁移 Leader,先执行切换(switchover)让其他成员成为 Leader,然后对原 Leader 重复第 3–4 步: - -```bash -kubectl exec -n $NAMESPACE $CLUSTER_NAME-0 -c postgres -- \ - patronictl switchover $CLUSTER_NAME --force -``` - -### 6. 恢复调度 - -待所有成员都位于期望节点后,取消对任何节点的 cordon,并移除临时标签/`nodeSelector`。 - -## 说明 - -- 逐个迁移成员,并在迁移下一个之前等待每个成员完全重新同步(`Lag = 0`),以使集群始终保持健康的法定数量。 -- 对于单实例集群,临时扩容到两个实例,让新成员在目标节点上完成同步,执行切换后再缩容回一个实例——以避免对唯一实例执行删除并重新克隆所导致的停机。 From d80a95e9c477be9ad0b24213b879f098760cb8a8 Mon Sep 17 00:00:00 2001 From: Jinpei Su Date: Thu, 18 Jun 2026 07:34:30 +0000 Subject: [PATCH 3/3] docs: address CodeRabbit review on PG solutions - CloudBeaver: retrieve superuser password from the operator-created Secret (postgres..credentials...) instead of a non-existent PGPASSWORD_SUPERUSER env var - node migration: label only the target node to avoid rescheduling onto the source Co-Authored-By: Claude Opus 4.8 (1M context) --- ...How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md | 8 +++++--- ...ow_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md | 8 ++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md b/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md index 4cd63077..cbd1cb24 100644 --- a/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md +++ b/docs/en/solutions/How_to_Deploy_CloudBeaver_for_PostgreSQL_Management.md @@ -139,13 +139,15 @@ Open the URL in a browser. kubectl -n get svc ``` -3. Enter the database user and password. The `postgres` superuser password is available in the cluster as an environment variable / Secret: +3. Enter the database user and password. The Operator stores each role's credentials in a Secret named `..credentials.postgresql.acid.zalan.do`. Retrieve the `postgres` superuser password from its Secret: ```bash - kubectl exec -n -0 -c postgres -- \ - bash -c 'echo $PGPASSWORD_SUPERUSER' + kubectl get secret postgres..credentials.postgresql.acid.zalan.do \ + -n -o jsonpath='{.data.password}' | base64 -d; echo ``` + The same Secret also carries `username`, `host` and `port` keys. + 4. (Optional) Set **Database** to the target database; otherwise CloudBeaver connects to the default `postgres` database. 5. Under **Access Management**, grant the current CloudBeaver user permission to use the new connection. 6. Save and test the connection. SQL editors can now be opened from the browser and queries executed against the PostgreSQL cluster. diff --git a/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md b/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md index b82b457b..efb7e789 100644 --- a/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md +++ b/docs/en/solutions/How_to_Migrate_a_PostgreSQL_Instance_to_Another_Node.md @@ -62,10 +62,14 @@ nodes (or use a `nodeSelector`/label that only the target nodes carry). Keep at least the target node schedulable. ```bash -# Example: label the source and target nodes, then select them -kubectl label node target=true --overwrite +# Label ONLY the target node(s) so the recreated pod can land there and nowhere else +kubectl label node target=true --overwrite ``` +Do **not** label the source node — labeling both source and target would let the +pod reschedule back onto the source. If you prefer cordoning over labels, cordon +all non-target nodes instead and skip the `nodeSelector` step below. + If you use a label-based selector, set it on the instance: ```bash