






















今天看了下新迁移的服务器,已经运行着 7 个 PostgreSQL 实例。随着自托管服务的增多,若单个服务都使用独立的数据库容器,会对服务器有限的硬件资源造成浪费。

同时,考虑到 immich 和 Plausible 本身对数据库版本有特定要求,暂不将其并入共享 PostgreSQL 实例。
但对其他应用而言,将数据库迁移到统一的 PostgreSQL 共享实例更为合理。这样不仅能减少基础内存占用,还能显著简化后续的统一备份与维护工作。
设立一个中心化 PostgreSQL 实例,compose.yml 配置示例如下:
# /home/dejavu/postgres-alpine-18/compose.yml
services:
postgres-alpine:
image: postgres:18.3-alpine3.23
container_name: postgres-alpine
restart: unless-stopped
deploy:
resources:
limits:
memory: 4G
networks:
- postgres-alpine
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- ./database:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 3s
retries: 8
start_period: 10s
command:
- "postgres"
- "-c"
- "max_connections=300"
- "-c"
- "shared_buffers=1GB"
- "-c"
- "work_mem=16MB"
- "-c"
- "maintenance_work_mem=512MB"
- "-c"
- "effective_cache_size=3GB"
- "-c"
- "random_page_cost=1.1"
networks:
postgres-alpine:
name: postgres-alpine
driver: bridge
# 如需 IPv6 支持
# 可参考 https://blog.dejavu.moe/posts/enable-ipv6-in-docker/
# enable_ipv6: true
启动服务:
sudo docker compose up -d
接下来,我们开始将现有服务迁移到该共享中心数据库。
我将容器数据库迁移的逻辑过程简化为以下 5 步:
compose.yml 模板,启动服务并观察日志;以 LiteLLM 服务的迁移过程为例,这是原来的 compose.yml 如下:
# /home/dejavu/litellm/compose.yml
services:
litellm:
image: ghcr.io/berriai/litellm:main-v1.81.14-stable
container_name: litellm
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
- ./vertex-key.json:/app/vertex-key.json
environment:
- GOOGLE_APPLICATION_CREDENTIALS=/app/vertex-key.json
- VERTEX_PROJECT=my-project
- VERTEX_LOCATION=us-central1
- LITELLM_MASTER_KEY=sk-some-words
- LITELLM_SALT_KEY=
- DATABASE_URL=postgresql://litellm:litellm@db:5432/litellm
command: ["--config", "/app/config.yaml", "--port", "4000"]
restart: unless-stopped
db:
image: postgres:18-alpine
container_name: litellm-db
restart: unless-stopped
environment:
- POSTGRES_DB=litellm
- POSTGRES_USER=litellm
- POSTGRES_PASSWORD=litellm
deploy:
resources:
limits:
memory: 256M
volumes:
- ./db:/var/lib/postgresql
先停止 LiteLLM 服务,并保持数据库服务运行
# 备份 Compose 模板
cp compose.yml compose.yml.bak
# 停止 litellm 应用
sudo docker compose stop litellm
# 导出旧数据库的数据
sudo docker exec -t litellm-db pg_dump -U litellm litellm -c > litellm_backup.sql
# 停止旧数据库
sudo docker compose down
登录共享的 PostgreSQL 实例:
sudo docker exec -it postgres-alpine psql -U postgres
执行以下 SQL 语句:
CREATE USER litellm WITH ENCRYPTED PASSWORD 'litellm';
CREATE DATABASE litellm;
ALTER DATABASE litellm OWNER TO litellm;
\q
导入备份数据
cat litellm_backup.sql | sudo docker exec -i postgres-alpine psql -U litellm -d litellm
接下来调整 compose.yml 应用编排配置:
# /home/dejavu/litellm/compose.yml
services:
litellm:
image: ghcr.io/berriai/litellm:main-v1.81.14-stable
container_name: litellm
# 加入中心数据库的 Docker 子网
networks:
- postgres-alpine
# 以上为新增字段
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
- ./vertex-key.json:/app/vertex-key.json
environment:
- GOOGLE_APPLICATION_CREDENTIALS=/app/vertex-key.json
- VERTEX_PROJECT=my-project
- VERTEX_LOCATION=us-central1
- LITELLM_MASTER_KEY=sk-some-words
- LITELLM_SALT_KEY=
- DATABASE_URL=postgresql://litellm:litellm@db:5432/litellm
command: ["--config", "/app/config.yaml", "--port", "4000"]
restart: unless-stopped
# 删除 db 服务
# 声明加入外部 Docker 子网
networks:
postgres-alpine:
external: true
重新启动服务并注意观察日志:
sudo docker compose up -d && sudo docker compose logs -f litellm
确认连接正常,数据库正确迁移,我们就可以删除备份了:
# 删除备份文件和旧目录
rm compose.yml.bak
rm litellm_backup.sql
sudo rm -rf ./db
第二个示例是 Miniflux,与前文一致,停止应用并导出数据:
# 停止 Miniflux 服务
sudo docker compose stop miniflux
# 导出旧数据库备份
sudo docker exec -t miniflux-db pg_dump -U miniflux miniflux -c > miniflux_backup.sql
# 停止并销毁容器
sudo docker compose down
# 备份 compose.yml
cp compose.yml compose.yml.bak
进入中心数据库容器:
sudo docker exec -it postgres-alpine psql -U postgres
初始化数据库与用户:
CREATE USER miniflux WITH ENCRYPTED PASSWORD 'miniflux';
CREATE DATABASE miniflux;
ALTER DATABASE miniflux OWNER TO miniflux;
\q
导入备份数据:
cat miniflux_backup.sql | sudo docker exec -i postgres-alpine psql -U miniflux -d miniflux
原来的 compose.yml 模板如下:
services:
miniflux:
image: miniflux/miniflux:2.2.17
container_name: miniflux
restart: unless-stopped
ports:
- "127.0.0.1:8081:8080"
depends_on:
db:
condition: service_healthy
networks:
- miniflux-internal
- warp-tunnel
- rsshub
- apprise
environment:
- DATABASE_URL=postgres://miniflux:miniflux@db/miniflux?sslmode=disable
# ...
db:
image: postgres:18-alpine
container_name: miniflux-db
restart: unless-stopped
networks:
- miniflux-internal
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=miniflux
- POSTGRES_DB=miniflux
volumes:
- ./db:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "miniflux"]
interval: 10s
start_period: 30s
networks:
warp-tunnel:
external: true
apprise:
external: true
rsshub:
external: true
miniflux-internal:
name: miniflux-internal
driver: bridge
我们需要修改 compose.yml 模板:
services:
miniflux:
image: miniflux/miniflux:2.2.17
container_name: miniflux
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
# 移除 db 服务依赖
networks:
- postgres-alpine # 新增 Docker 子网络
- warp-tunnel
- rsshub
- apprise
environment:
# 修改 PostgreSQL 连接配置,指向中心数据库
- DATABASE_URL=postgres://miniflux:miniflux@postgres-alpine:5432/miniflux?sslmode=disable
# ...
# 删除原来的 db 服务
networks:
warp-tunnel:
external: true
apprise:
external: true
rsshub:
external: true
# 替换原来的 miniflux-internal 子网络
postgres-alpine:
external: true
在 我的配置 中,Shlink 后端服务与 Web 仪表盘共用了一个数据库,需要同时迁移两个独立的数据库。
这是原来的 compose.yml 配置文件:
services:
db:
image: postgres:18-alpine
container_name: shlink-db
restart: unless-stopped
environment:
- POSTGRES_DB=shlink
- POSTGRES_USER=shlink
- POSTGRES_PASSWORD=shlink
volumes:
- ./data:/var/lib/postgresql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
# ...
valkey:
image: valkey/valkey:8.1.5-alpine
container_name: shlink-valkey
restart: unless-stopped
# ...
mercure:
image: dunglas/mercure:v0.17
container_name: shlink-mercure
restart: unless-stopped
# ...
shlink-backend:
image: shlinkio/shlink:5.0.1
container_name: shlink-backend
restart: unless-stopped
depends_on:
db:
condition: service_healthy
valkey:
condition: service_healthy
mercure:
condition: service_healthy
environment:
- DB_DRIVER=postgres
- DB_HOST=db
- DB_NAME=shlink
- DB_USER=shlink
- DB_PASSWORD=shlink
# ...
ports:
- "127.0.0.1:8080:8080"
shlink-web:
image: shlinkio/shlink-dashboard:0.2.3
container_name: shlink-web
user: "1000:1000"
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:3005:3005"
environment:
SHLINK_DASHBOARD_DB_DRIVER: postgres
SHLINK_DASHBOARD_DB_HOST: db
SHLINK_DASHBOARD_DB_PORT: 5432
SHLINK_DASHBOARD_DB_NAME: dashboard
SHLINK_DASHBOARD_DB_USER: shlink
SHLINK_DASHBOARD_DB_PASSWORD: shlink
迁移步骤如下:
# 停止应用服务
sudo docker compose stop shlink-backend shlink-web
# 导出 Shlink 后端数据库
sudo docker exec -t shlink-db pg_dump -U shlink shlink -c > shlink_backup.sql
# 导出 Shlink 仪表盘数据库库
sudo docker exec -t shlink-db pg_dump -U shlink dashboard -c > dashboard_backup.sql
# 停止并销毁容器
sudo docker compose down
# 进入中心数据库执行操作
sudo docker exec -it postgres-alpine psql -U postgres
执行 SQL 查询:
CREATE USER shlink WITH ENCRYPTED PASSWORD 'shlink';
CREATE DATABASE shlink;
ALTER DATABASE shlink OWNER TO shlink;
CREATE DATABASE dashboard;
ALTER DATABASE dashboard OWNER TO shlink;
\q
分别导入备份数据
# 导入 Shlink 后端数据库
cat shlink_backup.sql | sudo docker exec -i postgres-alpine psql -U shlink -d shlink
# 导入 Shlink 仪表盘数据库
cat dashboard_backup.sql | sudo docker exec -i postgres-alpine psql -U shlink -d dashboard
修改后的 compose.yml 结构类似这样:
services:
# 删除 db 服务
valkey:
image: valkey/valkey:8.1.5-alpine
container_name: shlink-valkey
restart: unless-stopped
command: "valkey-server --save 60 1 --loglevel warning --protected-mode no"
# 声明子网络
networks:
- postgres-alpine
volumes:
- ./valkey:/data
# ...
mercure:
image: dunglas/mercure:v0.17
container_name: shlink-mercure
restart: unless-stopped
# 声明子网络
networks:
- postgres-alpine
ports:
- "127.0.0.1:29090:80"
# ..
shlink-backend:
image: shlinkio/shlink:5.0.1
container_name: shlink-backend
restart: unless-stopped
# 声明子网络
networks:
- postgres-alpine
depends_on:
# 移除 db 服务依赖
valkey:
condition: service_healthy
mercure:
condition: service_healthy
environment:
- DB_DRIVER=postgres
- DB_HOST=postgres-alpine # 修改数据库主机名
- DB_NAME=shlink
- DB_USER=shlink
- DB_PASSWORD=shlink
# ...
ports:
- "127.0.0.1:8080:8080"
shlink-web:
image: shlinkio/shlink-dashboard:0.2.3
container_name: shlink-web
user: "1000:1000"
restart: unless-stopped
# 声明子网络
networks:
- postgres-alpine
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:3005:3005"
environment:
SHLINK_DASHBOARD_DB_DRIVER: postgres
SHLINK_DASHBOARD_DB_HOST: postgres-alpine # 修改数据库主机名
SHLINK_DASHBOARD_DB_PORT: 5432
SHLINK_DASHBOARD_DB_NAME: dashboard
SHLINK_DASHBOARD_DB_USER: shlink
SHLINK_DASHBOARD_DB_PASSWORD: shlink
# 声明 Docker 网络
networks:
postgres-alpine:
external: true
迁移完成后,建议检查中心数据库的状态,确保各库与用户权限配置无误。中心数据库应以稳为主,除非必要,否则尽量减少升级操作。
# 查看数据库列表
sudo docker exec -it postgres-alpine psql -U postgres -c "\l"
# 查看角色列表
sudo docker exec -it postgres-alpine psql -U postgres -c "\du"
对比迁移前后,虽然关停多余的 PostgreSQL 容器节省了一些 RAM 和磁盘占用,使得整体服务更加集中,但是也增加了「单点故障」风险,自行权衡利弊吧。

此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。