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. 启动与验证
- 构建镜像:
docker-compose build - 启动集群:
docker-compose up -d - 查看Patroni状态:
docker exec -it patroni1 patronictl list,确认主从节点正常运行 - 无SSL连接测试:
psql -h localhost -p 5432 -U postgres,输入密码postgres即可直接连接
关键注意事项
- 生产环境请勿关闭etcd认证,需配置etcd用户名密码并在Patroni中添加对应认证参数
- 无SSL连接仅适合内部可信网络,生产环境强烈建议开启SSL加密
- Citus Worker节点需通过Patroni API动态获取主节点地址,避免硬编码导致的故障
内容的提问来源于stack exchange,提问作者Sara
相关产品推荐
相关产品推荐

