You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署Citus+Patroni+etcd集群遇权限错误,求无SSL搭建方案

解决Docker中Citus+Patroni+etcd Postgres集群的权限错误与无SSL配置

一、解决"/var/lib/postgresql/data"权限错误

这个错误核心是容器内postgres用户(UID 999)没有挂载目录的读写权限,以下是可行解决方式:

1. 使用Docker Named Volume替代Bind Mount

Named Volume由Docker自动管理权限,初始化时会自动赋予postgres用户正确权限,是最省心的方案。在docker-compose.yml中替换bind mount为named volume:

volumes:
  postgres-data-1:  # 每个Patroni节点对应独立的named volume
  postgres-data-2:
  etcd-data-1:
  etcd-data-2:
  etcd-data-3:

然后在Patroni服务的volumes字段中使用:postgres-data-1:/var/lib/postgresql/data

2. 调整宿主机挂载目录权限

如果必须使用bind mount,手动给宿主机目录赋予UID 999的权限:

sudo chown -R 999:999 /path/to/host/postgres-data

rootless Docker环境下,需将宿主机UID映射到容器内的999,可通过uidmap工具配置,或启动容器时指定user: $(id -u):$(id -g),同时确保宿主机目录当前用户有读写权限。

3. 避免错误的用户配置

不要在Dockerfile或docker-compose中强制设置user: root运行Postgres,Postgres镜像默认会以postgres用户启动,强制root会导致初始化时权限切换失败。

二、从零搭建无SSL的Citus+Patroni+etcd集群

以下是完整可运行配置,包含Dockerfile、docker-compose.yml和patroni.yml,同时解决权限问题与无SSL需求:

1. Dockerfile(基于Citus镜像集成Patroni)

# 基于官方Citus镜像构建
FROM citusdata/citus:12.1

# 安装Patroni及etcd依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3-pip \
    python3-dev \
    && pip3 install patroni[etcd] \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# 复制Patroni配置文件到容器
COPY patroni.yml /etc/patroni.yml

# 暴露端口
EXPOSE 5432 8008

# 默认启动命令
CMD ["patroni", "/etc/patroni.yml"]

2. docker-compose.yml(包含etcd集群、Patroni节点、Citus Coordinator)

version: '3.8'

services:
  # etcd高可用集群(3节点)
  etcd1:
    image: bitnami/etcd:3.5
    environment:
      - ETCD_NAME=etcd1
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ENABLE_V2=true
    volumes:
      - etcd-data-1:/bitnami/etcd
    ports:
      - "2379:2379"

  etcd2:
    image: bitnami/etcd:3.5
    environment:
      - ETCD_NAME=etcd2
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ENABLE_V2=true
    volumes:
      - etcd-data-2:/bitnami/etcd

  etcd3:
    image: bitnami/etcd:3.5
    environment:
      - ETCD_NAME=etcd3
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ENABLE_V2=true
    volumes:
      - etcd-data-3:/bitnami/etcd

  # Patroni节点1
  patroni1:
    build: .
    environment:
      - PATRONI_NAME=patroni1
      - PATRONI_POSTGRESQL_DATA_DIR=/var/lib/postgresql/data
      - PATRONI_POSTGRESQL_USER=postgres
      - PATRONI_POSTGRESQL_PASSWORD=postgres
      - PATRONI_POSTGRESQL_LISTEN_ADDRESS=0.0.0.0
      - PATRONI_RESTAPI_LISTEN_ADDRESS=0.0.0.0:8008
      - PATRONI_ETCD_URLS=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
    volumes:
      - postgres-data-1:/var/lib/postgresql/data
    ports:
      - "5432:5432"
      - "8008:8008"
    depends_on:
      - etcd1
      - etcd2
      - etcd3

  # Patroni节点2
  patroni2:
    build: .
    environment:
      - PATRONI_NAME=patroni2
      - PATRONI_POSTGRESQL_DATA_DIR=/var/lib/postgresql/data
      - PATRONI_POSTGRESQL_USER=postgres
      - PATRONI_POSTGRESQL_PASSWORD=postgres
      - PATRONI_POSTGRESQL_LISTEN_ADDRESS=0.0.0.0
      - PATRONI_RESTAPI_LISTEN_ADDRESS=0.0.0.0:8008
      - PATRONI_ETCD_URLS=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
    volumes:
      - postgres-data-2:/var/lib/postgresql/data
    ports:
      - "5433:5432"
      - "8009:8008"
    depends_on:
      - etcd1
      - etcd2
      - etcd3

  # Citus Coordinator(连接Patroni主节点)
  citus-coordinator:
    image: citusdata/citus:12.1
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - COORDINATOR_HOST=patroni1
      - POSTGRES_PORT=5432
    ports:
      - "5434:5432"
    depends_on:
      - patroni1
      - patroni2

volumes:
  postgres-data-1:
  postgres-data-2:
  etcd-data-1:
  etcd-data-2:
  etcd-data-3:

3. patroni.yml(无SSL配置)

scope: postgres-cluster
namespace: /db/
name: "{{ env('PATRONI_NAME') }}"

restapi:
  listen: "{{ env('PATRONI_RESTAPI_LISTEN_ADDRESS') }}"
  connect_address: "{{ env('PATRONI_NAME') }}:8008"
  ssl: false  # 关闭Patroni REST API SSL

etcd:
  hosts: "{{ env('PATRONI_ETCD_URLS') }}"
  ssl: false  # 关闭etcd连接SSL

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        ssl: off  # 关闭Postgres SSL
        ssl_cert_file: ''
        ssl_key_file: ''
        ssl_ca_file: ''
        listen_addresses: '*'
        max_connections: 100
        shared_buffers: 128MB

  initdb:
    - encoding: UTF8
    - locale: en_US.UTF-8
    - data-checksums

  pg_hba:
    - host all all 0.0.0.0/0 md5  # 允许无SSL连接(测试环境用,生产建议限制IP)
    - host replication all 0.0.0.0/0 md5

postgresql:
  listen: "{{ env('PATRONI_POSTGRESQL_LISTEN_ADDRESS') }}:5432"
  connect_address: "{{ env('PATRONI_NAME') }}:5432"
  data_dir: "{{ env('PATRONI_POSTGRESQL_DATA_DIR') }}"
  pgpass: /tmp/pgpass
  authentication:
    superuser:
      username: "{{ env('PATRONI_POSTGRESQL_USER') }}"
      password: "{{ env('PATRONI_POSTGRESQL_PASSWORD') }}"
    replication:
      username: replicator
      password: replicatorpass
    rewind:
      username: rewind_user
      password: rewindpass

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

4. 启动与验证

  1. 构建镜像:docker-compose build
  2. 启动集群:docker-compose up -d
  3. 查看Patroni状态:docker exec -it patroni1 patronictl list,确认主从节点正常运行
  4. 无SSL连接测试:psql -h localhost -p 5432 -U postgres,输入密码postgres即可直接连接

关键注意事项

  • 生产环境请勿关闭etcd认证,需配置etcd用户名密码并在Patroni中添加对应认证参数
  • 无SSL连接仅适合内部可信网络,生产环境强烈建议开启SSL加密
  • Citus Worker节点需通过Patroni API动态获取主节点地址,避免硬编码导致的故障

内容的提问来源于stack exchange,提问作者Sara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:05:01