Docker 部署 PostgreSQL:数据库服务、pgvector 向量检索
PostgreSQL 是社区维护的开源关系数据库,严格遵循 ACID 事务,除标准 SQL 外还原生支持 JSON、数组等复合类型,靠多版本并发控制(MVCC)支撑高并发读写;更重要的是扩展性——通过插件机制可以给数据库加装新能力,地理检索用 PostGIS,向量检索用 pgvector。pgvector 为 PostgreSQL 增加 vector 向量类型、距离运算符和近似最近邻(ANN)索引,让"业务数据 + 语义检索"留在同一个库、同一个事务里,不必再引入独立向量数据库和同步链路。
部署结论
| 项目 | 本文采用的值 |
|---|---|
| 项目地址 | PostgreSQL · pgvector |
| 官方镜像 | pgvector/pgvector:0.8.6-pg18-bookworm |
| 项目版本 | PostgreSQL 18.6(pgvector 0.8.6) |
| 主部署方法 | Docker Compose + 版本化 pgvector/pgvector 预装镜像 |
| 备选方法 | 同一版本镜像的 docker run 临时体验 |
| 对外端口 | 127.0.0.1:5432(仅本机回环) |
| 持久化位置 | 命名卷 pgdata → 容器内 /var/lib/postgresql |
| 依赖服务 | 无(单容器) |
| 部署日期 | 2026-09-23 |
镜像与版本选择
pgvector/pgvector 镜像叠加在 PostgreSQL 官方镜像之上,本文固定使用 0.8.6-pg18-bookworm,避免 latest 或未声明大版本的 tag 漂移。
选 tag 时看三件事:
- 数据库版本:
18.6是本文验证的小版本,18跟随 18.x 最新小版本滚动,latest会跨大版本漂移。长期部署禁止使用latest,小版本升级是显式动作而不是意外。 - 基础系统:
bookworm基于 Debian 12。Debian 系变体适合直接使用预装扩展镜像;如果切换到 Alpine 或自行构建镜像,需要重新验证扩展包和数据目录。 - 架构:同一 tag 覆盖 amd64/arm64,拉取后以
docker image inspect的RepoDigests比对官方公示摘要。
pgvector 与 PostgreSQL 大版本已经同时编码在镜像 tag 中,升级时必须同时检查两者兼容性。
架构说明
pgvector 不是独立服务,而是加载进 PostgreSQL 服务端的扩展:扩展二进制已经安装在镜像中,对每个数据库执行一次 CREATE EXTENSION vector,该库即获得向量类型、距离运算符和 hnsw、ivfflat 两种索引访问方法。应用通过一条连接同时写业务行和向量列。
镜像由 PostgreSQL 官方基础层和 pgvector 扩展层组成。Compose 直接使用版本化预装镜像,避免读者在部署过程中临时构建扩展镜像。
正在准备渲染...
查看源码
flowchart LR
A[应用 / psql 客户端] -->|5432| B[容器: pgvector/pgvector 0.8.6-pg18-bookworm]
I[./init/*.sql<br/>首次初始化脚本] --> B
B --> C[(命名卷 pgdata<br/>/var/lib/postgresql)]前置条件
- Docker Engine 与 Compose 插件可用:
docker compose version有版本输出才能继续。 - 宿主机 5432 端口空闲:
lsof -i :5432无输出;被占用则把端口映射第一段的宿主机端口改为其他值。 - 磁盘余量:命名卷初始为几十 MB 量级,之后随表数据和索引增长。
国内网络直连镜像仓库失败时,优先配置 registry mirror 后再按本文步骤执行,Compose 中的官方镜像引用不需要改动;通过第三方加速拉取后,用下面的命令取回镜像摘要并与仓库页公示的 digest 比对,镜像源配置方法见Docker 镜像源配置教程。
docker image inspect <镜像> --format '{{json .RepoDigests}}'docker run 快速启动
只为感受产物,不作为长期形态。
QUICK_PASSWORD="$(openssl rand -hex 16)"
docker run --rm -d --name pg-quick \
--env POSTGRES_PASSWORD="$QUICK_PASSWORD" \
-p 127.0.0.1:5432:5432 \
pgvector/pgvector:0.8.6-pg18-bookworm--name自定义容器名;-d后台运行;-p端口映射;
快速部署成功后验证(临时实例使用初始化超级用户):
# 进入容器
docker exec -it pg-quick psql -U postgres
# 查询数据库版本信息
docker exec pg-quick psql -U postgres -tAc "SELECT version()"
# PostgreSQL 18.6 (Debian 18.6-1.pgdg12+2) on aarch64-unknown-linux-gnu ...注意本命令没有挂数据卷:数据写在容器运行时的匿名卷里,容器删除后不保留业务数据。体验完执行 docker stop pg-quick,随后进入正式部署。
Docker Compose 长期运行
长期运行需要固定的口令注入方式、初始化脚本挂载、健康检查和命名卷的版本管理,一个 compose.yaml 承载比记一串 docker run 参数可靠。
工作目录
postgres/
├── compose.yaml
├── .env
├── init/
│ ├── 01-schema.sql
│ └── 02-vector.sql
└── backups/创建 .env 配置文件
在目录下创建 .env 文件。口令通过随机值生成,不把可复用的密码写进文章:
# .env 文件(需设置权限 chmod 600,仅所有者可读)
POSTGRES_USER=postgres
POSTGRES_DB=appdb.env只保存本地配置和生成的口令,权限设为600。
或者可以使用命令一键初始化 .env 文件:
cat > .env <<'EOF'
POSTGRES_USER=postgres
POSTGRES_DB=appdb
EOF
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 32)" >> .env
chmod 600 .env该命令会创建或覆盖当前目录下的 .env 文件;运行后不要把 .env 提交到版本库。
编写 compose.yaml 文件
services:
postgres:
image: pgvector/pgvector:0.8.6-pg18-bookworm
restart: unless-stopped
container_name: pg-service
shm_size: 256mb
ports:
- "127.0.0.1:5432:5432" # 仅本地监听,通过应用或代理访问
environment:
POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: ${POSTGRES_DB:?set POSTGRES_DB in .env}
TZ: Asia/Shanghai
volumes:
- pgdata:/var/lib/postgresql
- ./init:/docker-entrypoint-initdb.d:ro # 初始化脚本目录(可选)
deploy:
resources:
limits:
cpus: '2' # 限制 CPU 使用率
memory: 4G # 限制最大内存
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pgdata:restart: unless-stopped让宿主机重启后数据库随 Docker 自启,手动 stop 则不复活;${POSTGRES_PASSWORD:?...}缺值时启动直接失败而不是空口令裸奔;volumes分别解决"数据活过容器"和"新库自动建表";- healthcheck 让
docker compose ps的healthy成为可脚本化的成功信号。
挂载路径有大版本陷阱:PostgreSQL 18 起数据目录变为 /var/lib/postgresql/18/docker,镜像声明卷随之改为 /var/lib/postgresql,上面的写法适用于 18 及以上,且保留跨大版本 pg_upgrade --link 快速路径的前提。
警告:若改用 17 或更低版本镜像,数据卷必须挂载到 /var/lib/postgresql/data;挂 /var/lib/postgresql 不会持久化——运行时会自动创建匿名卷接管数据,容器删除重建后数据随之丢失。
也可以不用命名卷而挂宿主机目录(bind mount):./binddata:/var/lib/postgresql。重建容器后数据应继续保留,宿主机目录里会出现 18/ 子目录。两种挂载的取舍:命名卷由 Docker 管理权限、跨主机一致,适合默认选择;bind mount 路径直观、方便 rsync 式冷备份,但在 Linux 上宿主机目录属主要与容器内 postgres 用户(UID 999)匹配,否则 initdb 报权限错误。
启动前先静态校验:
docker compose config --quiet && echo "config OK".env 缺口令时该命令直接报错退出。校验通过后:
docker compose up -d初始化 01-schema.sql
init/01-schema.sql 演示首次初始化(建一张纯业务表):
CREATE TABLE documents (
id bigserial PRIMARY KEY,
title text NOT NULL
);
INSERT INTO documents (title) VALUES ('baseline-business-row');init/02-vector.sql 在首次创建的 appdb 中启用扩展:
CREATE EXTENSION IF NOT EXISTS vector;验证 PostgreSQL 服务
下列命令用于分层验收:先检查容器状态,再检查 PostgreSQL 版本、初始化脚本和 pgvector 扩展。
服务状态——健康检查从 starting 变为 healthy 表示可接受连接:
docker compose ps
# NAME IMAGE STATUS
# pg-service pgvector/pgvector:0.8.6-pg18-bookworm Up ... (healthy)数据库接口——服务端版本与初始化脚本结果:
docker compose exec postgres psql -U postgres -d appdb -tAc "SELECT version()"
# PostgreSQL 18.6 (Debian 18.6-1.pgdg12+2) on aarch64-unknown-linux-gnu ...
docker compose exec postgres psql -U postgres -d appdb -tAc "SELECT count(*) FROM documents"
# 1
docker compose logs postgres 2>&1 | grep 'docker-entrypoint-initdb.d'
# /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01-schema.sql扩展验收——预装镜像已经包含 pgvector,初始化脚本会在 appdb 中启用扩展:
docker compose exec postgres psql -U postgres -d appdb -tAc "SELECT extversion FROM pg_extension WHERE extname = 'vector'"
# 0.8.6启用并验证 pgvector
每个数据库都需要单独启用扩展。首次创建 appdb 时,init/02-vector.sql 自动执行;已有数据卷切换到本文镜像后,手动执行以下命令:
docker compose exec -T postgres psql -U postgres -d appdb \
-c 'CREATE EXTENSION IF NOT EXISTS vector;' \
-c "SELECT extversion FROM pg_extension WHERE extname = 'vector';"不要删除现有 pgdata;只替换镜像并重建容器即可。大版本不一致时不能复用数据卷,必须按“升级与回滚”章节执行迁移。
连接数据库与基本使用
容器内命令行(免密,走 trust 的本地套接字):
# 查看当前数据库信息
docker compose exec -T postgres psql -U postgres -d template1 -c '\l' -c '\du'
# 链接数据库
docker compose exec postgres psql -U postgres -d appdb常用元命令:
\l -- 列出数据库:appdb / postgres / template0 / template1
\dt -- 列出当前库的表:public.documents(owner: postgres)
\du -- 列出角色:postgres(Superuser, Create role, Create DB, ...)
\d 表名 -- 查看表结构;\conninfo 查看当前连接
\c database_name -- 切换到另一个数据库
CREATE DATABASE database_name; -- 创建一个新的数据库退出用 \q。日常 SQL 与其他 PostgreSQL 无异,下面演示容器场景最常踩坑的三件事:专用应用账号、最小授权、连接串。
-- 为业务连接创建专用账号;口令自行生成,不要用示例值
CREATE ROLE appuser LOGIN PASSWORD '应用口令';
GRANT CONNECT ON DATABASE appdb TO appuser;
GRANT USAGE, CREATE ON SCHEMA public TO appuser;GRANT ... ON SCHEMA public 在新版本 PostgreSQL 里是必要动作:15 起普通用户对 public 模式默认没有建表权限。表级读写授权按需执行:
GRANT SELECT, INSERT, UPDATE, DELETE ON documents TO appuser;
GRANT USAGE ON SEQUENCE documents_id_seq TO appuser;应用侧连接串(宿主机端口映射为回环时从本机连):
postgresql://appuser:应用口令@127.0.0.1:5432/appdb验收权限边界时,以 appuser 经 TCP 连接执行 SELECT current_user, current_database() 应返回 appuser|appdb;执行 DROP TABLE documents 应返回 ERROR: must be owner of table documents,确认应用账号不能修改表结构。
远程访问与时区配置
常见误解是"远程访问要改 postgresql.conf 和 pg_hba.conf"。官方镜像的出厂配置已经替你做好了:SHOW listen_addresses 应返回 *(容器内监听所有网卡),pg_hba.conf 默认规则为——
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
host all all all scram-sha-256容器内本地连接免密(trust 只作用于套接字与回环),其余地址进来一律走 scram-sha-256 口令认证。所以从局域网其他机器连入,不需要进容器改任何配置文件,要控制的只是端口暴露面:
- 只给本机上的应用:保持
127.0.0.1:5432:5432。 - 给同网段某台应用服务器:把映射改为宿主机内网 IP 绑定(如
192.168.1.10:5432:5432),配合宿主机防火墙白名单,仍不要裸绑0.0.0.0暴露公网。 - 跨网段:优先 SSH 隧道或 VPN,而不是放宽数据库认证。
时区:容器默认 SHOW timezone 返回 Etc/UTC。要改成东八区,在 Compose 服务下加 command: 覆写服务端参数(改环境变量 TZ 不影响已 initdb 的数据目录默认值):
command: ["postgres", "-c", "timezone=Asia/Shanghai"]docker compose up -d --force-recreate 后检查 SHOW timezone 应返回 Asia/Shanghai。这只影响服务端显示时区;跨时区存储建议统一 timestamptz 类型,由客户端决定展示。
首次初始化:业务表与向量索引
以文档语义检索为例,假设嵌入模型输出 768 维向量:
-- 创建一个存储文档块和对应向量的表
CREATE TABLE document_chunks (
id BIGSERIAL PRIMARY KEY,
content TEXT NOT NULL, -- 文档文本内容
embedding vector(1536), -- 向量,维度是1536
metadata JSONB, -- 可以存一些元信息,比如来源文件、页码等
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入示例数据。这里的向量值是随便写的,仅作演示。
INSERT INTO document_chunks (content, embedding) VALUES
('PostgreSQL是一个功能强大的开源关系数据库。', '[0.1, 0.2, 0.3, ...]'), -- 这里省略了1536个数字
('pgvector扩展为PostgreSQL增加了向量相似性搜索能力。', '[0.4, 0.5, 0.6, ...]'),
('RAG应用利用向量数据库检索相关信息来增强大模型生成。', '[0.7, 0.8, 0.9, ...]');
CREATE TABLE articles (
id bigserial PRIMARY KEY,
title text NOT NULL,
embedding vector(768) NOT NULL
);
CREATE INDEX ON articles USING hnsw (embedding vector_cosine_ops);查询用余弦距离运算符 <=>,$1 为查询向量参数:
SELECT id, title, 1 - (embedding <=> $1) AS similarity
FROM articles
ORDER BY embedding <=> $1
LIMIT 10;POSTGRES_PASSWORD、POSTGRES_DB 这类镜像环境变量只在数据目录为空的首次初始化时生效。卷已存在时改 .env 重启不会改口令,改口令执行 SQL:
ALTER USER postgres WITH PASSWORD '新口令';
ALTER USER appuser WITH PASSWORD '新口令';pgvector 用法与调优
先用一个 4 维玩具例子看查询形状。建表插入三条文档向量(实际维度由嵌入模型决定,768/1536 都常见):
CREATE TABLE demo_articles (id bigserial PRIMARY KEY, title text, embedding vector(4) NOT NULL);
INSERT INTO demo_articles (title, embedding) VALUES
('PostgreSQL 备份手册', '[0.9,0.1,0.1,0.0]'),
('向量索引调优笔记', '[0.85,0.2,0.15,0.05]'),
('番茄炒蛋做法', '[0.05,0.9,0.1,0.2]');
SELECT id, title, round((1 - (embedding <=> '[0.9,0.1,0.1,0.0]'))::numeric, 4) AS similarity
FROM demo_articles
ORDER BY embedding <=> '[0.9,0.1,0.1,0.0]'
LIMIT 3;
-- id | title | similarity
-- ----+---------------------+------------
-- 1 | PostgreSQL 备份手册 | 1.0000
-- 2 | 向量索引调优笔记 | 0.9895
-- 3 | 番茄炒蛋做法 | 0.17141 - 距离 把余弦距离换算成"越大越相似",配 WHERE 1 - (embedding <=> $1) > 0.5 即可过滤低相关命中。下面是生产规模的硬约束与参数。
存储上限:vector 最多 16,000 维,halfvec(半精度)同样 16,000 维;单条 vector 占用 4 × 维度 + 8 字节,容量规划按此估算。超过 2,000 维无法用默认方式建索引,可改存 halfvec(索引上限 4,000 维)、用 binary quantization(64,000 维),或做降维。
距离运算符与索引操作符类必须配对:<-> L2、<#> 内积(返回负值,因为 Postgres 索引只支持升序扫描)、<=> 余弦、<+> L1。vector_l2_ops 建的索引只加速 L2 查询,规划器不会用 L2 索引跑余弦查询,每个要用的距离函数都要单独建索引。
HNSW 与 IVFFlat 的取舍:HNSW 查询更好、构建更慢更占内存,空表即可建;IVFFlat 构建快省内存,用召回换速度,且必须表里有数据后再建(需要聚类训练)。
-- HNSW:默认 m = 16、ef_construction = 64
CREATE INDEX ON articles USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- IVFFlat:lists 起步取 行数/1000(最多约 100 万行),更大表取 sqrt(行数)
CREATE INDEX ON articles USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);查询期精度参数:HNSW 默认 hnsw.ef_search = 40,调大换召回;IVFFlat 默认 ivfflat.probes = 1,经验起步值 sqrt(lists):
SET hnsw.ef_search = 100;
SET ivfflat.probes = 10;近似索引的过滤发生在索引扫描之后:带 WHERE 时命中行数可能少于 LIMIT。0.8.0 起可开启迭代索引扫描,自动扩大扫描直到凑够结果:
SET hnsw.iterative_scan = strict_order;安装与使用其他 PostgreSQL 扩展
三步部署的镜像分层同样服务其他扩展,按来源分四条路径。
其一,contrib 内置扩展直接用。官方 postgres 镜像已带 PostgreSQL contrib 套件,pg_available_extensions 可查清单,CREATE EXTENSION 即可安装。需要写共享内存的扩展要额外预加载:未配置预加载时查询会报 pg_stat_statements must be loaded via "shared_preload_libraries";在 Compose 服务下加一行后重建并重新检查:
command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"]其二,PGDG apt 包可以按自定义 Dockerfile 的方式装进派生镜像。包名格式 postgresql-<主版本>-<扩展名>,PostGIS 即 postgresql-18-postgis-3;只有在预装镜像不能满足需求时才采用这条路径,并重新验证构建结果。
其三,使用版本化的预装集成镜像。本文的 pgvector/pgvector 即此类:直接使用匹配 PostgreSQL 大版本的 tag,每个数据库执行一次 CREATE EXTENSION vector;。
其四,在存量部署内编译安装扩展:需要完整编译工具链,且每次镜像重建都要重做,只在无法换镜像、扩展也没有可用包时考虑。
自动启用扩展给所有新建数据库使用:把 SQL 文件放进 /docker-entrypoint-initdb.d(如 02-vector.sql),文件按名称排序执行,*.sql 以 POSTGRES_USER 身份运行。该目录只在数据目录为空时执行一次,之后不再运行,失败也不会重跑。
pgvector 升级到新镜像后,在每个已启用的数据库执行:
ALTER EXTENSION vector UPDATE;
SELECT extversion FROM pg_extension WHERE extname = 'vector';日常运维
宿主机连接:psql -h 127.0.0.1 -p 5432 -U appuser -d appdb。容器内部的本地连接走 trust 免密,这是镜像初始化行为,不影响外部连接仍需口令。
查看日志与重启:
docker compose logs -f postgres
docker compose restart postgresdocker compose stop 只停容器、保留卷。危险操作是 docker compose down -v:该命令连同命名卷 pgdata 一起删除,数据库文件随之不可恢复,执行前必须先备份(见下方数据与恢复边界)。
数据与恢复边界:恢复单元是命名卷 pgdata、.env 口令、compose.yaml 和 ./init 脚本目录。逻辑备份直接写入宿主机 backups/,不写入 PostgreSQL 数据目录:
mkdir -p backups
docker compose exec -T postgres pg_dump -U postgres -d appdb -Fc \
> "backups/appdb-$(date +%Y%m%d).dump"定时备份(宿主机 crontab 每日凌晨 2 点,crontab 中 % 需转义为 \%):
0 2 * * * cd /opt/postgres-vector && mkdir -p backups && docker compose exec -T postgres pg_dump -U postgres -d appdb -Fc > "backups/appdb-$(date +\%F).dump"恢复到新库(先建库,再使用 pg_restore 导入):
docker compose exec -T postgres createdb -U postgres appdb_restore
docker compose exec -T postgres psql -U postgres -d appdb_restore \
-c 'CREATE EXTENSION IF NOT EXISTS vector;'
BACKUP_FILE="$(ls -1t backups/appdb-*.dump | head -n 1)"
docker compose exec -T postgres pg_restore -U postgres -d appdb_restore --exit-on-error \
< "$BACKUP_FILE"
docker compose exec -T postgres psql -U postgres -d appdb_restore \
-tAc "SELECT count(*) FROM documents"
# 1定期抽样恢复一份备份,确认 documents 和向量表都能读取;文件系统级冷备份需要先 docker compose stop 停写,通用卷归档与恢复验收见镜像数据备份与恢复教程。
容器默认 /dev/shm 只有 64MB,并行查询或并行索引构建耗尽共享内存时报 ERROR: could not resize shared memory segment ... : No space left on device。上调 Compose 的 shm_size 即可;提高 maintenance_work_mem 加速 HNSW 构建时,shm_size 至少要等于 maintenance_work_mem。
升级与回滚
版本来源固定在镜像 tag 上:pgvector/pgvector:0.8.6-pg18-bookworm 同时声明 PostgreSQL 和 pgvector 版本。升级是切换到新的版本化 tag、拉取镜像并重建容器:
docker compose pull postgres
docker compose up -d --force-recreatePostgreSQL 小版本升级(18.x 之间)或 pgvector 小版本升级(0.8.x 之间)都应先在测试环境验证,再修改 Compose 中的完整镜像 tag。重建后对每个启用扩展的库执行 ALTER EXTENSION vector UPDATE;。
升级后的业务验收至少覆盖:SELECT version() 为新版本、docker compose ps 恢复 healthy、核心检索 SQL 正常返回。通用 Compose 更新与回退操作见服务更新回滚教程。
大版本升级(例如 18 → 19)不能让新旧版本共用一个已初始化数据目录,两条官方路径:
- 逻辑迁移:升级前
pg_dump全量导出,挂新卷用新版本镜像初始化后灌入;注意恢复前目标库要先CREATE EXTENSION,否则含扩展类型的表无法灌入。 - 物理迁移:
pg_upgrade。PostgreSQL 18 起数据目录布局为/var/lib/postgresql/<大版本>/docker,卷挂在/var/lib/postgresql正是pg_upgrade --link快速路径的前提。
大版本切换不可逆:新版本一旦写入数据目录,回退只能依赖升级前的备份恢复。执行前必须完成一份 pg_dump 并验证可恢复。小版本回滚切换回旧的完整镜像 tag 并重建容器即可,若旧镜像拒绝启动新数据目录,同样走备份恢复。
生产环境安全加固
- 端口暴露按远程访问一节的最小面原则执行:默认回环,跨机走内网绑定或隧道,不要把 5432 暴露公网。
- 不要把
POSTGRES_HOST_AUTH_METHOD设为trust:那会让任何能连到端口的客户端免密可连;镜像默认已是"非回环一律scram-sha-256",保持不动。 - 应用一律用普通账号(
appuser)+ 表级授权,不要共用postgres超级用户。 - 口令可用 Docker Secrets 注入:
postgres镜像的_FILE变量仅支持POSTGRES_PASSWORD、POSTGRES_USER、POSTGRES_DB、POSTGRES_INITDB_ARGS四项。 - 备份文件
backup-*.sql含全库数据,按敏感数据保管;.env权限 600。 - 使用预装镜像时仍应固定 tag,定期检查镜像来源和漏洞扫描结果,不要在生产环境临时切换到未验证的 tag。
- 通用暴露面、权限与镜像供应链基线见生产环境安全教程。
- 只有在需要自定义认证规则时才维护
postgresql.conf和pg_hba.conf;默认认证规则已经覆盖本机免密和远程 SCRAM 认证。
常见问题
CREATE EXTENSION vector 报 extension "vector" is not available。
pgvector/pgvector 镜像已经包含扩展二进制。先确认镜像 tag 与 PostgreSQL 大版本匹配,再在目标数据库执行 CREATE EXTENSION IF NOT EXISTS vector;已有数据卷不会自动补跑初始化脚本。
应用连不上数据库。
按序排查:docker compose ps 是否 healthy;客户端到的是否为宿主机映射端口(容器内 5432 对外可能不同);连接串走回环还是内网 IP——非回环连接被 scram-sha-256 拦下时报口令认证错误,报 no pg_hba.conf entry 则是映射端口挂到了别的进程;宿主机 lsof -i :5432 确认监听方。
容器启动失败,日志有 initdb 权限错误。
bind mount 场景下 Linux 宿主机目录属主与容器内 postgres 用户(UID 999)不一致所致:chown -R 999:999 宿主机目录,或改用命名卷。
改了 .env 里的口令或库名,重启后没生效。
镜像环境变量只在空数据目录首次初始化时生效。口令用 ALTER USER ... WITH PASSWORD 修改;库名对应执行 CREATE DATABASE。
FATAL: database "appdb" does not exist
当前数据卷中不存在 appdb,需要使用初始化超级用户创建数据库;全新部署通常由 POSTGRES_DB=appdb 自动创建。
# 创建已有数据卷缺失的数据库
docker compose exec -T postgres psql -U postgres -d postgres -c 'CREATE DATABASE appdb OWNER postgres;'
# 查看当前数据库信息
docker compose exec -T postgres psql -U postgres -d template1 -c '\l' -c '\du'
# 链接数据库
docker compose exec postgres psql -U postgres -d appdb重建容器后数据消失。
大概率卷挂错路径:17 及以下版本必须挂 /var/lib/postgresql/data,挂到 /var/lib/postgresql 时数据实际写入了运行时自动创建的匿名卷。用 docker inspect <容器> --format '{{json .Mounts}}' 检查是否存在非预期的匿名卷;恢复只能依赖备份。
首次启动的初始化脚本没执行完。
/docker-entrypoint-initdb.d 只在数据目录为空时整体执行一次;一个脚本失败会导致容器退出,编排器带着已初始化的数据目录重启后,剩余脚本不会继续。看日志 running /docker-entrypoint-initdb.d/... 停在哪个文件,修复后如数据目录已被部分写入,需要清卷重来。
时间显示差 8 小时。
服务端默认 Etc/UTC,按远程访问与时区一节加 command: ["postgres", "-c", "timezone=Asia/Shanghai"];长期方案优先用 timestamptz 列存绝对时间。
带 WHERE 过滤的最近邻查询返回不足 LIMIT 条。
近似索引先扫索引后过滤,属于机制而非故障,按调优一节开启 hnsw.iterative_scan。
could not resize shared memory segment。
默认 /dev/shm 64MB 不够,上调 shm_size;并行 HNSW 构建场景下 shm_size 不小于 maintenance_work_mem。
镜像拉取超时。
守护进程配置 registry mirror 后重试;更换加速源不改变镜像引用,拉取后比对 digest 确认内容一致。
总结
本文使用版本化 pgvector/pgvector:0.8.6-pg18-bookworm,以 Compose、命名卷和初始化脚本部署 PostgreSQL 18.6 与 pgvector 0.8.6。正式使用前应验证容器健康、扩展版本、应用账号权限和重建后的数据;大版本升级或回退必须依赖已经验证可恢复的 pg_dump 备份。