数据库高可用集群管理运维后端【免费下载链接】patroniA template for PostgreSQL High Availability with Etcd, Consul, ZooKeeper, or Kubernetes项目地址https://gitcode.com/gh_mirrors/pa/patroni点击查看免费下载本篇技术指南围绕 Patroni 项目仓库中的 OpenShift 示例配置 展开系统讲解如何在 OpenShift 的restrictedSCCSecurity Context Constraints约束下部署一套三副本的 PostgreSQL 高可用集群。你将掌握镜像构建、模板参数化部署、持久化与非持久化两种模式的选择、RBAC 权限模型以及容器内 Patroni 配置自动生成的完整链路可直接复制到自己的 OpenShift 项目中使用。OpenShift 适配的核心问题动态 UID/GID 与 restricted SCCOpenShift 与标准 Kubernetes 的一个显著差异在于安全策略默认的restrictedSCC 不允许容器以任意 UID 运行Pod 会被分配一个随机的、高数值的 UID通常大于 10000并且运行用户无法在构建阶段预先确定。传统的容器镜像如果写死了postgres用户的 UID/GID在 OpenShift 下就会遇到数据目录权限不足、进程无法启动等问题。Patroni 仓库为此在 kubernetes/Dockerfile 和 kubernetes/entrypoint.sh 中做了专门的适配使其可以在标准的restrictedSCC 下直接运行。镜像层的权限预置kubernetes/Dockerfile 基于postgres:16官方镜像构建除了常规的 Patroni 安装pip3 install githttps://github.com/patroni/patroni.git#eggpatroni[kubernetes]即带 Kubernetes DCS 依赖的安装方式外还包含三个面向 OpenShift 的关键步骤chmod 775 $PGHOME将/home/postgres目录权限放宽使非属主的随机 UID 也能进入并读写chmod 664 /etc/passwd让容器启动脚本有能力改写/etc/passwd这正是下面动态 UID 注入所依赖的前提USER postgres默认仍以postgres用户身份启动便于与基础镜像的目录属主保持一致。容器启动时的动态 UID/GID 注入kubernetes/entrypoint.sh 是适配的核心脚本开头执行了这样一段逻辑if [[ $UID -ge 10000 ]]; then GID$(id -g) sed -e s/^postgres:x:[^:]*:[^:]*:/postgres:x:$UID:$GID:/ /etc/passwd /tmp/passwd cat /tmp/passwd /etc/passwd rm /tmp/passwd fi其原理是当 OpenShift 注入的运行时 UID 大于等于 10000即restrictedSCC 的典型随机 UID 范围时脚本用sed将/etc/passwd中postgres行的 UID/GID 替换为当前实际值。由于构建阶段已经chmod 664 /etc/passwd容器内用户可以完成这一改写。此后进程虽然以随机 UID 运行但在/etc/passwd中的身份仍被解析为postgres从而满足 PostgreSQL 对数据目录属主的校验逻辑同时规避了 OpenShift 对固定 UID 的限制。部署准备创建项目并构建 Patroni 镜像按照 OpenShift 示例 README 的流程首先创建一个独立的测试项目oc new-project patroni-test接下来需要准备两样东西PostgreSQL 基础镜像ImageStream和 Patroni 应用镜像。原文档给出的命令如下oc import-image postgres:10 --confirm -n openshift oc new-build https://github.com/patroni/patroni --context-dirkubernetes -n openshift其中两点需要说明oc import-image postgres:10用于将官方postgres镜像导入到openshift命名空间形成 ImageStream当前仓库的 kubernetes/Dockerfile 已基于postgres:16因此实际使用时建议按需调整为postgres:16或直接使用你所在集群已导入的版本原文档特别提示如果该模板要提供给多个用户共享使用上述命令应在共享命名空间如openshift中执行这样所有项目都能通过docker-registry.default.svc:5000/${NAMESPACE}/patroni:latest拉取镜像而不必各自重复构建。oc new-build以仓库kubernetes目录为上下文构建这与 kubernetes/Dockerfile 的COPY entrypoint.sh /指令相吻合——entrypoint 脚本就位于该目录内。两种部署模板Ephemeral 与 Persistentkubernetes/openshift-example目录下提供了两套 OpenShift Templatekind: Template清单原文档明确指出二者唯一的区别是 StatefulSet 是否请求持久化存储模板文件Template 名称存储方式适用场景template_patroni_ephemeral.ymlpatroni-pgsql-ephemeralemptyDir测试、验证部署流程template_patroni_persistent.yamlpatroni-pgsql-persistentPVC默认 5GiReadWriteOnce生产级数据持久化Ephemeral 模板的警告原文直述WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.——所有数据在 Pod 销毁后即丢失仅限测试使用。两者在 StatefulSet 上的存储差异具体体现为Ephemeral 版在volumes中声明emptyDir: {}见 template_patroni_ephemeral.ymlPersistent 版则通过volumeClaimTemplates声明 PVC并将volumes指向persistentVolumeClaim见 template_patroni_persistent.yaml。此外Persistent 版额外加入了一个名为fix-perms的 initContainerinitContainers: - command: - sh - -c - mkdir -p /home/postgres/pgdata/pgroot/data chmod 0700 /home/postgres/pgdata/pgroot/data image: docker-registry.default.svc:5000/${NAMESPACE}/patroni:latest name: fix-perms volumeMounts: - mountPath: /home/postgres/pgdata name: ${APPLICATION_NAME}这个 initContainer 的意义在于PVC 首次挂载时往往为空目录且属主为root而容器实际以随机 UID 运行因此需要先创建数据目录并收紧权限chmod 0700为 PostgreSQL 的初始化扫清障碍。这正是 OpenShift 场景下「存储卷权限修正」的标准做法。模板参数全解两套模板的参数定义基本一致Persistent 版仅多一个PVC_SIZE。下面是完整的参数表值均来自模板的parameters段默认值参数名默认值说明APPLICATION_NAMEpatroni-ephemeral/patroni-persistent所有资源对象的统一标签与应用名PATRONI_CLUSTER_NAME同APPLICATION_NAMEPatroni 集群名即 DCS scope决定 ConfigMap 归属PATRONI_PRIMARY_SERVICE_NAMEpatroni-ephemeral-primary等指向 primary 的只读 Service按role: primary选择器PATRONI_REPLICA_SERVICE_NAMEpatroni-ephemeral-replica等指向 replica 的只读 Service按role: replica选择器MEMORY_LIMIT512Mi容器内存上限模板中预留供资源配额使用NAMESPACEopenshiftPatroni 与 PostgreSQL ImageStream 所在的命名空间PATRONI_SUPERUSER_USERNAMEpostgres初始化用的超级用户账号PATRONI_SUPERUSER_PASSWORDpostgres超级用户密码写入 Secret生产环境务必覆盖PATRONI_REPLICATION_USERNAMEpostgres复制账号用户名PATRONI_REPLICATION_PASSWORDpostgres复制账号密码写入 Secret生产环境务必覆盖SERVICE_ACCOUNTpatroniocp/patroni-persistentPod 与 RoleBinding 使用的服务账号PVC_SIZE仅 Persistent5Gi持久卷申请大小通过oc new-app实例化模板时可用-p 参数名值覆盖任意默认值例如oc new-app patroni-pgsql-ephemeral -p PATRONI_SUPERUSER_PASSWORD强密码 -p PATRONI_REPLICATION_PASSWORD强密码部署步骤安装模板并实例化应用如果模板需要被整个集群共享先将其安装到openshift命名空间oc create -f templates/template_patroni_ephemeral.yml -n openshift然后切换到自己的项目并实例化oc new-app patroni-pgsql-ephemeraloc new-app会按模板展开所有对象。原文档给出了部署完成后的验证方法——检查 ConfigMap$ oc get configmap NAME DATA AGE patroniocp-config 0 1m patroniocp-leader 0 1m这两个 ConfigMap 正是 Patroni 在 Kubernetes/OpenShift DCS 模式下的核心存储patroniocp-config存放动态配置dynamic configurationpatroniocp-leader存放 leader 选举状态。它们的命名规则是${SERVICE_ACCOUNT}-config与${SERVICE_ACCOUNT}-leader与模板中默认的SERVICE_ACCOUNTpatroniocp完全对应。模板内部对象与 RBAC 权限模型深度解析模板通过objects字段一次性声明了 9 类资源理解它们各自的作用是安全运维的前提。Service 三件套集群入口与角色分流${PATRONI_CLUSTER_NAME}ClusterIP端口 5432→5432无选择器的占位 Service配合同名 Endpoints 对象由 Patroni 自行维护成员列表${PATRONI_PRIMARY_SERVICE_NAME}选择器含role: primary始终将流量导向当前主节点${PATRONI_REPLICA_SERVICE_NAME}选择器含role: replica将流量导向只读副本。其中role: primary/role: replica标签由 Patroni 自身在运行过程中动态打上写入 Pod 标签因此这些 Service 天然支持读写分离接入。Secret 与密码注入模板创建一个${PATRONI_CLUSTER_NAME}类型的 Secret其中包含superuser-password和replication-password两个键随后 StatefulSet 中通过secretKeyRef将其注入为PATRONI_SUPERUSER_PASSWORD/PATRONI_REPLICATION_PASSWORD环境变量——密码不会明文出现在 Pod 定义中。StatefulSet 与环境变量注入链StatefulSet 以podManagementPolicy: OrderedReady、replicas: 3有序拉起三个 Pod并设置updateStrategy: OnDelete避免滚动更新打乱选举。每个 Pod 注入的环境变量分为两类来自 Downward API 的动态值PATRONI_KUBERNETES_POD_IPstatus.podIP、PATRONI_KUBERNETES_NAMESPACEmetadata.namespace、PATRONI_NAMEmetadata.name即 Pod 名来自模板参数的固定值PATRONI_KUBERNETES_LABELS格式{application: xxx, cluster-name: yyy}作为 DCS 资源归属过滤条件、PATRONI_SCOPE、PATRONI_POSTGRESQL_DATA_DIR/home/postgres/pgdata/pgroot/data、PATRONI_POSTGRESQL_LISTEN0.0.0.0:5432、PATRONI_RESTAPI_LISTEN0.0.0.0:8008。容器还配置了基于 REST API 的只读探针readinessProbe: httpGet: scheme: HTTP path: /readiness port: 8008 initialDelaySeconds: 3 periodSeconds: 10 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 3/readiness是 Patroni REST API 的标准健康端点与 patroni/api.py 中实现的就绪检查对应只有节点达到可接受写入或可接受只读状态时才返回 200从而保证 Pod 只有在真正就绪时才会被纳入 Service 端点。RBAC最小权限模型模板为${SERVICE_ACCOUNT}创建了一个 Role权限被严格限定在configmapscreate/get/list/patch/update/watch/delete其中delete仅patronictl remove需要注释已明确说明endpointsget/patch/update外加create/list/watch后三个仅在启用 endpoints 模式时需要delete同样仅patronictl remove需要podsget/list/patch/update/watch用于读取成员状态与打角色标签。随后通过RoleBinding将该 Role 绑定到服务账号。这里值得注意的一个细节是模板末尾还声明了名为patroni-k8s-ep-access的ClusterRole仅允许get名为kubernetes的 endpoints及其ClusterRoleBinding。模板中对此有明确注释这些权限仅当集群部署在非default命名空间、且开启PATRONI_KUBERNETES_BYPASS_API_SERVICEtrue时需要。bypass_api_service的语义在 patroni/dcs/kubernetes.py 中体现为bypass_api_service not self._ctl and config.get(bypass_api_service)即绕过 Kubernetes Service 直连 API Server其内部实现见 kubernetes.py 的 ApiClient会通过解析 endpoints 缓存 API Server 地址列表并在访问失败时自动刷新缓存、轮换节点这正是模板中该 ClusterRole 需要getkubernetesendpoints 的原因。容器内的 Patroni 配置生成链路OpenShift 模板通过环境变量把运行时信息注入容器而最终 Patroni 的 YAML 配置文件由 kubernetes/entrypoint.sh 在启动时动态生成。生成的patroni.yml包含以下关键片段bootstrap: dcs: postgresql: use_pg_rewind: true pg_hba: - host all all 0.0.0.0/0 md5 - host replication ${PATRONI_REPLICATION_USERNAME} ${PATRONI_KUBERNETES_POD_IP}/16 md5 - host replication ${PATRONI_REPLICATION_USERNAME} 127.0.0.1/32 md5 initdb: - auth-host: md5 - auth-local: trust - encoding: UTF8 - locale: en_US.UTF-8 ->oc get pods -L rolePatroni 会自动为节点打上role: primary/role: replica标签确认存在一个主节点与两个副本节点即代表选举正常。进入主节点容器后可通过patronictl list查看集群成员与复制延迟kubernetes/README.md 中展示了标准 Kubernetes 下的同类输出示例OpenShift 环境结果一致。需要说明的运维边界密码类模板参数PATRONI_SUPERUSER_PASSWORD、PATRONI_REPLICATION_PASSWORD在生产环境必须通过-p覆盖默认值且应结合 OpenShift 的 Secret 管理实践如外部 Secrets 同步使用Ephemeral 模板仅适用于功能验证数据落盘需求应使用 Persistent 模板并合理设置PVC_SIZE模板中 Role 对configmaps/endpoints的delete权限仅服务于patronictl remove等显式清理操作日常运维无需担心误删若将集群部署在非default命名空间且启用了PATRONI_KUBERNETES_BYPASS_API_SERVICEtruepatroni-k8s-ep-accessClusterRoleBinding 中的namespace字段必须改为实际部署命名空间。仓库还提供了 Jenkinsfile 示例描述了一条可选的 CI 链路创建独立的 pgbench Pod 对 Patroni 集群执行基准与正确性测试可作为模板部署后的自动化验证参考。赞分享数据库高可用集群管理运维后端【免费下载链接】patroniA template for PostgreSQL High Availability with Etcd, Consul, ZooKeeper, or Kubernetes项目地址https://gitcode.com/gh_mirrors/pa/patroni点击查看免费下载相关推荐Algoliasearch-client-php与Laravel集成构建闪电般快速的搜索体验Algoliasearch client php与Laravel集成构建闪电般快速的搜索体验 Algoliasearch client php是一个功能齐全且数据库高可用集群管理运维后端PDF补丁丁免费强大的PDF处理工具箱完整指南PDF补丁丁免费强大的PDF处理工具箱完整指南 你是否曾经为PDF文档的编辑问题而烦恼想要修改PDF书签却找不到合适的工具需要合并多个PDF文件但不想付费数据库高可用集群管理运维后端Meshery 设计模式基于 CNPG Operator 在 GKE 上部署高可用 PostgreSQL 集群postgreSQL cluster 0.0.1Meshery 设计模式基于 CNPG Operator 在 GKE 上部署高可用 PostgreSQL 集群postgreSQL cluster 0.0.云原生微服务运维DevOps上一篇Rodauth-Rails部署指南生产环境配置与性能优化最佳实践下一篇Kronos源码探秘NTPClient与DNSResolver组件的设计与实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
KuGouMusicApi功能清单详解:131个接口分类梳理,从登录、榜单到AI推荐全覆盖 KuGouMusicApi功能清单详解:131个接口分类梳理,从登录、榜单到AI推荐全覆盖 【免费下载链接】KuGouMusicApi 酷狗音乐 Node.js API service 项目地址: https://gitcode.com/gh_mirrors/ku/KuGouMusicApi
KuGouMusicApi 是一款酷狗音乐 Node.js AP… · 2026/9/25 7:24:58
Atlas 300V 24G部署YOLO全攻略:环境搭建到AscendCL推理实践 把 Atlas 300V 24G 插进服务器之后,很多人第一反应是敲nvidia-smi,然后陷入沉默。屏幕不亮、没有显示输出、风扇在转,但系统里根本找不到"显卡"——这其实是 Atlas 这类 AI 推理加速卡和普通显卡最大的认知差。它是运算加速卡吗&am… · 2026/9/25 7:24:51
moto 对 AWS Comprehend 的模拟实现:功能覆盖矩阵、底层机制与测试实战 Mock测试 【免费下载链接】moto A library that allows you to easily mock out tests based on AWS infrastructure. 项目地址: https://gitcode.com/gh_mirrors/mo/moto 点击查看 免费下载 moto 项目中的 docs/docs/services/comprehend.rst 服务文档列出了 moto… · 2026/9/25 7:24:51
iOS原生CLI编程助手:本地运行CodeLlama的实践与架构 1. 这不是“把Claude塞进手机”,而是重构AI编程助手的终端形态我把 Claude Code 装进了手机,然后把它开源了——这句话乍听像极了某款App上架通知,但实际远比这复杂得多。它既不是调用官方API封装个壳子,也不是简单移植网页版到iO… · 2026/9/25 7:56:54
Dart SDK Front-End Builder 机制深度解析:源码与 dill 的统一程序元素构造抽象 编程语言编译器语言运行时标准库开发工具 【免费下载链接】sdk The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more. 项目地址: https://gitcode.com/gh_mirrors/sdk1/sdk 点击查看 免费下载 本文以 Dart SDK 前端编译器… · 2026/9/25 7:56:54
快马前端生成器:零基础入门的可视化代码教学工具 1. 快马不是“快码”,而是新手前端真正的第一块跳板我带过不少零基础转行的学员,前年有个刚毕业的文科生,连<div>和<span>都分不清,硬是靠快马生成的登录页,三个月后拿下某电商公司的前端实习岗。他没写过… · 2026/9/25 7:56:54
PHP连接Redis全攻略:扩展安装、哨兵集群与避坑实践 不少做PHP的朋友第一次接触Redis,都是从“装个扩展,然后new Redis()”开始的。但等到真正要上生产环境、要搭集群、要处理高并发下的连接异常时,才会发现Redis的客户端世界远比想象中复杂。这一篇实战实录,我专门把Redis扩展的几种… · 2026/9/25 7:56:48
iOS音视频开发核心:AVFoundation底层原理与实战 1. 这不是“又一个视频播放教程”,而是 iOS 视频开发的底层通关地图AVFoundation 是 iOS/macOS 上处理音视频最核心、最底层的框架,它不像 UIKit 那样“开箱即用”,也不像第三方库那样封装友好。它更像是一套精密的工业级工具箱——螺丝刀、游… · 2026/9/25 7:56:42
Simple Allow Copy:一键解锁网页复制限制的Chrome插件实战指南 你有没有遇到过这种情况:想从某个网页上复制一段文字,结果右键菜单被禁用;鼠标选中文字后,一按CtrlC,弹窗提示“该内容受版权保护”;或者更气人的是——复制倒是能复制,但粘贴出来后面自动跟了一… · 2026/9/25 7:56:42
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37