开发期想要一个随手起、不污染主机、带管理界面的 PostgreSQL。
Compose 是最低摩擦方案。
目录结构
~/pg-stack/
├── docker-compose.yml
├── .env
├── init/
│ └── 01-init.sql
└── data/ # 卷挂载点(git 忽略)
docker-compose.yml
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${PG_USER}
POSTGRES_PASSWORD: ${PG_PASS}
POSTGRES_DB: ${PG_DB}
# 让 init/*.sql 在首次启动时跑
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d:ro
ports:
- "127.0.0.1:5432:5432" # 只在 localhost 暴露
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 3s
retries: 5
pgadmin:
image: dpage/pgadmin4:latest
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASS}
PGADMIN_LISTEN_PORT: 80
ports:
- "127.0.0.1:5050:80"
depends_on:
db:
condition: service_healthy
volumes:
- pgadmin-data:/var/lib/pgadmin
volumes:
pgadmin-data:
.env(不要进 git)
PG_USER=appuser
PG_PASS=change-me-some-long-random-string
PG_DB=appdb
PGADMIN_EMAIL=admin@local
PGADMIN_PASS=change-me-too
init/01-init.sql
-- 启用常用扩展
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- 只读分析账号
CREATE USER analytics WITH PASSWORD 'analytics-pass';
GRANT CONNECT ON DATABASE appdb TO analytics;
GRANT USAGE ON SCHEMA public TO analytics;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO analytics;
启动
docker compose up -d
docker compose ps
docker compose logs -f db # 看初始化
校验
# 通过 psql 客户端连
docker compose exec db psql -U appuser -d appdb -c '\dx'
# 或者本地 psql
psql -h 127.0.0.1 -U appuser -d appdb
pgAdmin 打开 http://localhost:5050,登录用 .env 里的邮箱密码。
进去后 "Add new server":
- Host: db(容器名,pgAdmin 在同一 Compose 网络)
- Port: 5432
- User/Password: 同 .env
备份 / 恢复
# 备份
docker compose exec -T db pg_dump -U appuser -d appdb -Fc > backup-$(date +%F).dump
# 恢复(连接已存在的数据库会失败,先 drop)
docker compose exec -T db psql -U postgres -c 'DROP DATABASE appdb;'
docker compose exec -T db psql -U postgres -c 'CREATE DATABASE appdb OWNER appuser;'
docker compose exec -T db pg_restore -U appuser -d appdb < backup-2026-05-20.dump
升级 Postgres 大版本
主版本(如 16 → 17)跨越时 数据文件不兼容,需要 dump/restore:
docker compose exec -T db pg_dumpall -U postgres > all.sql
# 改 image: postgres:17-alpine
# 清空 ./data 重启
docker compose down
rm -rf ./data
docker compose up -d
docker compose exec -T db psql -U postgres < all.sql
踩过的坑
- 端口写成
5432:5432而不是127.0.0.1:5432:5432:整个公网都能连到
你的数据库,扫描器十分钟内就来撞密码。一定要绑 127.0.0.1。 ./data不要用 NFS 挂载点,PostgreSQL 对fsync行为要求严格,
NFS 上跑会丢数据。init/只在 数据目录为空 时执行;如果你后来改了 init.sql 想重跑,
得先docker compose down -v清掉。- Alpine 镜像比 Debian 小但 glibc 差异偶尔翻车(特别是某些 extension),
生产用postgres:16-bookworm更稳。
登录后参与评论。