Patroni Helm Chart自动创建数据库Schema时root角色不存在错误排查
解决Patroni Helm Chart自动创建数据库Schema的问题
你遇到的核心问题有两个:一是Patroni容器不会自动执行/docker-entrypoint-initdb.d/下的脚本(因为Patroni的启动流程和原生Postgres容器逻辑不同),二是手动执行时用root用户没有对应的Postgres数据库角色权限。下面是针对性的解决方案:
为什么脚本没自动执行?
原生Postgres容器的entrypoint会在数据库第一次初始化时扫描/docker-entrypoint-initdb.d/目录并执行脚本,但Patroni是通过自身进程管理Postgres实例的,它有独立的初始化逻辑,不会触发这个目录的脚本执行。
解决方案1:利用Patroni的post_init钩子(推荐)
Patroni原生支持在Postgres实例初始化完成后执行自定义脚本,这是最贴合Patroni架构的实现方式:
- 更新你的ConfigMap,添加Patroni配置和初始化脚本:
kind: ConfigMap apiVersion: v1 metadata: name: {{ template "patroni.fullname" . }} labels: app: {{ template "patroni.fullname" . }} release: {{ .Release.Name }} data: patroni.yml: | # 保留你原有的Patroni配置,新增post_init部分 post_init: - command: ["psql", "-U", "postgres", "-f", "/mnt/init.sql"] timeout: 300 init.sql: |- -- 替换为你的Schema创建语句,示例: CREATE SCHEMA IF NOT EXISTS my_app_schema; CREATE TABLE IF NOT EXISTS my_app_schema.user_info ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
- 在StatefulSet的volumeMounts中添加ConfigMap挂载,将
init.sql映射到容器内的/mnt/init.sql:
volumeMounts: - mountPath: /mnt/init.sql name: patroni-config subPath: init.sql # 保留你原有的其他volumeMounts配置 volumes: - name: patroni-config configMap: name: {{ template "patroni.fullname" . }}
这样,当Patroni完成Postgres实例初始化时,会自动以postgres用户执行你的Schema创建脚本,无需手动干预。
解决方案2:自定义Supervisord进程执行初始化脚本
如果你的Helm Chart不支持直接修改Patroni配置,也可以通过新增Supervisord进程来实现初始化逻辑,确保只执行一次且用正确的用户:
- 扩展你的ConfigMap,添加一个启动控制脚本:
data: init-schema.sh: | #!/bin/bash # 标记文件,避免重复执行初始化 MARKER_FILE="/var/lib/postgresql/data/.schema_initialized" if [ ! -f "$MARKER_FILE" ]; then # 等待Postgres服务启动完成 until psql -U postgres -c "SELECT 1" > /dev/null 2>&1; do echo "Waiting for Postgres to become available..." sleep 2 done # 执行Schema创建脚本 echo "Running schema initialization..." psql -U postgres -f /docker-entrypoint-initdb.d/init.sql # 创建标记文件 touch "$MARKER_FILE" echo "Schema initialization completed." fi # 保持进程运行(Supervisord需要进程持续存活) tail -f /dev/null init.sql: |- **DB SCHEMA TO BE CREATED**
- 在StatefulSet中挂载脚本并赋予执行权限:
volumeMounts: - mountPath: /docker-entrypoint-initdb.d/ name: patroni-config - mountPath: /opt/init-schema.sh name: patroni-config subPath: init-schema.sh volumes: - name: patroni-config configMap: name: {{ template "patroni.fullname" . }} defaultMode: 0755 # 确保脚本有执行权限
- 修改Supervisord配置,新增一个初始化进程:
# 在你的Supervisord配置中添加以下内容 [program:init-schema] command=/bin/bash /opt/init-schema.sh user=postgres autostart=true autorestart=false startretries=3 stdout_logfile=/var/log/supervisor/init-schema.log stderr_logfile=/var/log/supervisor/init-schema.err
这个进程会在Pod启动时以postgres用户运行,等待Postgres可用后执行脚本,并通过标记文件避免每次重启重复执行。
手动执行的正确方式(用于测试)
如果需要手动验证脚本,一定要切换到postgres用户执行,不要用root:
# 直接在外部执行 oc exec -it postgres-ha-test-patroni-0 -- su - postgres -c "psql -f /docker-entrypoint-initdb.d/init.sql" # 或者进入容器后切换用户 oc exec -it postgres-ha-test-patroni-0 bash su - postgres psql -f /docker-entrypoint-initdb.d/init.sql
内容的提问来源于stack exchange,提问作者Apurva




