Docker Swarm集群中Postgres:10周期性Shutdown但仍存活问题
从你的日志和配置来看,postgres出现周期性关闭恢复的核心原因是健康检查脚本在Docker Swarm环境下无法正常连接数据库,导致Swarm判定容器不健康并重启它。因为你挂载了持久化数据卷,容器重启时不需要重新初始化,直接启动postgres,所以表现为数据库进程周期性关闭后恢复。
具体来说,健康检查脚本中使用hostname -i获取容器IP的方式在Swarm的overlay网络环境下存在问题:
hostname -i可能返回多个IP地址(比如容器的overlay网络IP和本地回环IP),导致psql的--host参数错误,连接失败- 即使返回单个IP,Swarm环境下容器的IP可能会动态变化,依赖这个IP进行健康检查不可靠
1. 修复健康检查脚本,改用Unix Socket连接
Unix Socket是postgres默认的连接方式,比TCP连接更可靠,且不受IP地址变化影响。修改你的健康检查脚本如下:
#!/bin/bash set -eo pipefail user="${POSTGRES_USER:-postgres}" db="${POSTGRES_DB:-$POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD:-}" args=( --username "$user" --dbname "$db" --quiet --no-align --tuples-only ) if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then exit 0 fi exit 1
去掉--host参数后,psql会自动使用Unix Socket(/var/run/postgresql/.s.PGSQL.5432)连接,避免了IP相关的问题。
2. 移除Swarm不支持的container_name配置
在Docker Swarm模式下,container_name选项会被忽略,且可能限制服务的调度能力(比如无法运行多个副本)。从你的docker-compose.yml中删除这一行:
container_name: db_jackrabbit
3. 验证健康检查配置
确保健康检查的参数合理:
HEALTHCHECK --interval=30s --timeout=30s --retries=3 \ CMD healthcheck
当前的配置是每30秒检查一次,超时30秒,重试3次后标记为不健康,这个配置是合理的,不需要调整。
4. 检查Swarm服务的重启策略
Swarm服务默认的重启策略是any(无论容器退出原因都会重启),如果希望避免健康检查失败后的频繁重启,可以调整为on-failure策略:
db_jackrabbit: # ... 其他配置 deploy: restart_policy: condition: on-failure max_attempts: 5
这样只有当容器异常退出时才会重启,避免健康检查误判导致的频繁重启。
修改后重新部署服务:
docker stack deploy -c docker-compose.yml <your-stack-name>
然后查看容器日志,确认postgres不再出现周期性的database system is shut down提示,且健康检查状态为healthy:
docker service logs <your-service-name> docker service inspect --format '{{.Status.TaskStatus.State}}' <your-service-name>
内容的提问来源于stack exchange,提问作者yuklia

