腾讯云 Ubuntu 24.04 用 Docker 部署 PostgreSQL 完整实战指南 📅 发布时间:2026/9/15 2:24:24 👁 浏览次数: 刚处理完一台腾讯云 Ubuntu 24.04 服务器上的 PostgreSQL 部署顺手帮朋友救了一次“裸装翻车”现场。他那台机器照着一篇旧教程敲apt install postgresql结果装的是 Ubuntu 自带的 PostgreSQL 16数据目录在/var/lib/postgresql/16/main配置文件散落一地远程连接又卡在pg_hba.conf上折腾到半夜还没好。我接手后直接换了个思路全部推倒用 Docker 部署。今天这篇就把整个流程拆开揉碎写清楚从选型、安装环境、编写 Compose 文件到日常备份和踩坑排查一次性讲完。我先说结论腾讯云 Ubuntu 24.04 加 Docker 加 PostgreSQL 这套组合非常适合个人项目、中小团队内部服务甚至是准备上生产的业务库。你不需要懂太多底层编译不需要操心系统包版本混乱只要把目录映射、端口、认证和备份管好一样能跑得比裸装还稳。1. 为什么我推荐容器化部署而不是直接 apt 装 PostgreSQL1.1 裸装 PostgreSQL 的三个痛点很多人拿到一台云服务器第一反应是apt install postgresql。这条路在 Ubuntu 24.04 上确实能装但不代表省心。我遇到过的典型问题有三个。版本跟系统绑定。Ubuntu 24.04 默认软件源里带的 PostgreSQL 可能是 16如果你需要 17或者某些兼容性更好的分支版本就得额外添加 PGDG 源加完源还要处理优先级稍不留神就把系统自带的包搞坏。数据目录和配置位置太分散。裸装的 PostgreSQL数据文件在/var/lib/postgresql/16/main配置文件在/etc/postgresql/16/main日志又在别的地方。备份要记一堆路径迁移要手动搬目录想换台机器重建环境时特别痛苦。权限和用户管理不够透明。postgres系统用户、pg_hba.conf的认证规则、Unix Socket 权限这些对新手来说都是坑。我之前见过有人为了方便直接改成trust认证等于把数据库裸奔在公网上风险非常大。1.2 Docker 部署把复杂度关进“盒子里”容器化之后PostgreSQL 对宿主机的侵入降到了最低。依赖隔离。PostgreSQL 运行在独立的文件系统里不需要在宿主机上装一堆依赖也不会污染 Ubuntu 的系统环境。卸载的时候直接删容器和镜像宿主机几乎没有残留。数据目录可控。容器内的数据目录是固定的比如官方postgres:16镜像默认使用/var/lib/postgresql/data。我们通过-v或 Compose 的volumes把它映射到宿主机某个目录比如/data/postgres/data。以后要备份、迁移只需要操作这个宿主机目录逻辑清晰很多。版本切换简单。想升级 PostgreSQL 大版本不再需要pg_upgrade那套复杂流程。我可以先备份数据再换一个镜像 Tag调整参数后重新起容器。虽然不能保证数据文件完全无缝升级但环境切换的成本比裸装小太多了。1.3 为什么数据库适配容器化这件事已经成熟早些年有人说数据库不适合容器因为状态数据不好管理。但如今官方 PostgreSQL 镜像已经原生支持 Docker 的初始化机制、健康检查和持久化卷只要把数据目录正确挂载出来容器重启、宿主机重启数据都不会丢。我常把容器里的 PostgreSQL 比作一台“移动版数据库主机”。你不需要关心硬件细节不用操心系统服务怎么注册只要定义好端口和存储它就是一个可以被随时停止、恢复、迁移的服务。腾讯云的轻量服务器或 CVM 上跑这套尤其顺因为底层网络和磁盘 I/O 都很稳定。2. 腾讯云环境准备与 Docker 安装2.1 服务器选择和安全组配置我这次用的是腾讯云标准型 CVM系统镜像选的 Ubuntu 24.04 LTS配置是 2 核 4G。对一个小型业务库来说这个规格完全够用。如果你只是跑个人项目1 核 2G 也能凑合但建议把内存加到 4G避免 PostgreSQL 在并发稍高时被 OOM 杀掉。拿到服务器后第一步不是装 Docker而是先把安全组和防火墙想清楚。腾讯云 CVM 默认安全组一般只开放 22、80、443 等端口PostgreSQL 默认端口是 5432如果你想从本地 Navicat、DBeaver 远程连接必须在腾讯云控制台的安全组里放行 5432。如果你用的是腾讯云轻量应用服务器入口不在“安全组”而是在“防火墙”页面加规则。两边配置原理一样都是允许来源 IP 访问目标端口。这里有个建议来源不要填0.0.0.0/0只填你办公楼或家里的公网 IP能少很多扫描爆破。2.2 在 Ubuntu 24.04 上安装 Docker 的正确姿势很多 Ubuntu 安装教程会让你直接apt install docker.io我一般不推荐这么干。Ubuntu 源里的 docker.io 版本更新慢而且默认不带 Compose 插件后面用docker compose时还得额外装比较别扭。我更推荐直接用 Docker 官方源的 docker-ce。安装过程如下# 更新系统基础包 sudo apt update sudo apt install -y ca-certificates curl gnupg # 添加 Docker 官方 GPG 密钥 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg # 添加 Docker 软件源 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 再次更新并安装 Docker sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装完成后加上当前用户进 docker 组省得每次敲命令都要 sudosudo usermod -aG docker $USER # 重新登录服务器后生效然后验证一下docker --version docker compose version能看到版本号就说明环境没问题。注意一点这里用的docker-compose-plugin提供的是docker compose子命令中间有空格不是老版本的docker-compose。我后文提到的所有命令都基于新版写法。2.3 镜像加速与拉取策略国内服务器直接拉 Docker Hub 镜像有时候会比较慢。Docker 官方提供了配置 registry mirror 的机制你可以在/etc/docker/daemon.json里配置镜像加速地址。基本格式是这样{ registry-mirrors: [https://你的加速地址] }配置完执行sudo systemctl restart docker生效。镜像加速地址变化快这里我就不写具体的了装完 Docker 后搜一下“Docker 镜像加速”通常能找到可用的。如果你访问 Docker Hub 速度还行其实这一步可以跳过。顺带说一句别用docker pull拉取时中断就反复重试PostgreSQL 官方镜像分层很多断点续传不总是有效。实在不行可以在另一台网络环境好的机器上提前拉好再导出导入这是后话。3. 用 Docker Compose 部署 PostgreSQL 实例3.1 设计目录结构我习惯把状态数据和应用配置分开。在宿主机上我规划了这样的目录结构/data/postgres/ ├── data # PostgreSQL 数据文件 └── backup # 数据库备份文件创建目录并处理权限sudo mkdir -p /data/postgres/{data,backup}为什么要把backup目录放在宿主机而不是容器里因为容器本身是易失的备份文件如果在容器内容器一删就全没了。映射到宿主机后我还能直接把备份文件同步到腾讯云 COS 或者其它对象存储。关于数据目录权限官方postgres:16镜像内部是用postgres用户跑的UID 是 999。如果你直接把宿主机空目录挂载进去容器启动时会因为权限不足报错。稳妥的做法是提前归好属主sudo chown -R 999:999 /data/postgres/data3.2 编写 docker-compose.yml我模拟了一份可以直接上线的 Compose 配置services: postgres: image: postgres:16 container_name: postgres restart: always environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: 替换成强密码 POSTGRES_DB: appdb TZ: Asia/Shanghai PGTZ: Asia/Shanghai ports: - 5432:5432 volumes: - /data/postgres/data:/var/lib/postgresql/data - /data/postgres/backup:/backup command: - postgres - -c - shared_buffers256MB healthcheck: test: [CMD-SHELL, pg_isready -U postgres] interval: 10s timeout: 5s retries: 5几个关键点我展开讲一下。POSTGRES_PASSWORD这个环境变量只在首次初始化数据目录时生效。如果数据目录已经存在且初始化过再改这个值不会重置密码。很多人不知道这一点后面我会再提。POSTGRES_DB首次启动时官方镜像会自动创建一个名为appdb的数据库。如果你不设置默认只会创建postgres库。TZ和PGTZ设置时区为上海。这样数据库的now()返回的是北京时间日志时间也正常。很多教程不会提这两个变量结果部署完发现数据库时间和服务器差 8 小时排查半天。command里的shared_buffers256MB这是 PostgreSQL 核心内存参数。对 4G 内存的机器256MB 起步比较稳。如果你服务器内存只有 1G建议改成 128MB给操作系统和文件缓存留足空间。healthcheck让 Docker 周期性执行pg_isready方便我们通过容器状态判断数据库是否真正就绪而不是只看进程有没有起来。3.3 启动容器并验证配置写好后执行cd /data/postgres docker compose up -d首次启动会从 Docker Hub 拉取postgres:16镜像时间取决于网络状况。拉完后容器会自动初始化数据目录、创建超级用户和默认数据库。查看容器状态docker ps正常会看到postgres容器状态是Up健康检查列是healthy。如果启动失败用下面命令看日志docker logs -f postgres日志里如果出现chmod: changing permissions of /var/lib/postgresql/data: Operation not permitted这类权限错误大概率就是宿主机目录属主没设对回到chown -R 999:999那一步重新处理。3.4 初始化业务账号和数据库容器起来后第一步进入容器内执行 psqldocker exec -it postgres psql -U postgres此时你会进入 PostgreSQL 的命令行。现在开始创建业务账号和数据库-- 创建一个业务用户密码换成实际使用的强密码 CREATE USER appuser WITH PASSWORD 替换成强密码; -- 创建业务库并指定属主 CREATE DATABASE appdb OWNER appuser; -- 切换到 appdb \c appdb -- 给 appuser 授予 schema 权限 GRANT ALL ON SCHEMA public TO appuser;这里有个细节PostgreSQL 在 15 版本之后默认不再允许普通用户随意在publicschema 下建表。如果你用appuser连接appdb后想直接建表必须像上面那样显式授权。这是很多从 MySQL 转过来的朋友最容易踩的坑。如果你是远程用 DBeaver 或 Navicat 连接需要把认证方式也确认清楚。官方镜像默认在pg_hba.conf里使用scram-sha-256认证而不是 MySQL 那种caching_sha2_password。只要你设置了POSTGRES_PASSWORD客户端用密码登录即可。4. 部署后的使用、备份与恢复4.1 最常用的 psql 命令进入容器后我经常用这些命令快速检查数据库状态# 进入容器 docker exec -it postgres bash # 切换用户并进入 psql su - postgres -c psql # 或者直接用容器环境变量里的用户 psql -U postgres在 psql 里下面这些指令是最常用的-- 查看所有数据库 \l -- 切换数据库 \c appdb -- 查看当前库所有表 \dt -- 查看某个表结构 \d table_name -- 查看所有角色/用户 \du -- 查看当前连接数 SELECT count(*) FROM pg_stat_activity; -- 查看 PostgreSQL 版本 SELECT version();如果你不习惯命令行也可以从本地用图形化工具连接。前提是腾讯云安全组已经放行 5432并且服务器上没有额外的 iptables 规则拦截。4.2 备份数据库强烈建议从第一天就开始我见过太多次“数据库崩了才发现从没备份”的事故。容器部署 PostgreSQL 让备份命令简化到了几行。使用pg_dump做单库逻辑备份docker exec -t postgres pg_dump -U postgres -d appdb -F c -f /backup/appdb_$(date %F_%H%M).dump解释一下参数-F c自定义压缩格式体积小便于后面pg_restore恢复。-f /backup/...备份文件写到容器内/backup路径对应宿主机/data/postgres/backup。备份完宿主机上可以直接看到文件ls -lh /data/postgres/backup/恢复也同样简单docker exec -i postgres pg_restore -U postgres -d appdb --clean --if-exists /backup/appdb_xxx.dump--clean表示在导入前先清除已存在的同名对象适合覆盖恢复。如果你是从零恢复到一个空库可以去掉--clean。4.3 定期备份落脚本和计划任务手动备份不是长久之计。我一般在宿主机上写一个备份脚本/data/postgres/backup.sh#!/bin/bash DATE$(date %F_%H%M) docker exec -t postgres pg_dump -U postgres -d appdb -F c -f /backup/appdb_${DATE}.dump # 只保留最近 7 天备份 find /data/postgres/backup -name appdb_*.dump -mtime 7 -delete然后加执行权限sudo chmod x /data/postgres/backup.sh再配置 crontabcrontab -e添加一行每天凌晨 2 点执行0 2 * * * /data/postgres/backup.sh /var/log/postgres_backup.log 21这里把标准输出和错误都重定向到日志方便以后排查备份是否成功。如果你担心磁盘占用可以把备份定期上传腾讯云 COS或者做异地同步。4.4 更新镜像和切换 PostgreSQL 版本Docker 部署还有一个隐藏优势换版本相对可控。升级小版本比如从 16.3 升到 16.4只需要# 先备份 docker exec -t postgres pg_dump -U postgres -d appdb -F c -f /backup/appdb_before_update.dump # 拉取新镜像 docker pull postgres:16.4 # 停止旧容器 cd /data/postgres docker compose down # 修改镜像版本号然后启动 docker compose up -d大版本升级比如从 16 升到 17不能直接复用数据目录。官方 PostgreSQL 的大版本升级需要执行pg_upgrade在容器里的操作更复杂。一般情况下我会选择“逻辑迁移”也就是先用pg_dump导出旧库再在新版本的容器里pg_restore导入。这样虽然慢一点但风险低、可回滚。真要做大版本升级我建议先在测试环境跑一遍流程别拿线上库直接试。5. 常见问题与排查技巧实录5.1 远程连接不上到底卡在哪一层这是被问得最多的问题。现象很统一本地 Navicat 连不上腾讯云上的 PostgreSQL提示超时或者拒绝连接。排查顺序很重要我一般按这四步走第一看 PostgreSQL 是否在监听所有网卡。容器里默认监听0.0.0.0你可以在宿主机执行docker exec -it postgres bash -c cat /var/lib/postgresql/data/postgresql.conf | grep listen_addresses如果值是localhost当然连不上。但官方镜像默认配置往往是注释状态实际监听0.0.0.0。大多数情况不是这里的问题。第二看腾讯云安全组。登录腾讯云控制台找到实例所属安全组确认入站规则里有没有TCP:5432。没有就添加上并限定来源 IP。第三看宿主机防火墙。Ubuntu 24.04 默认可能没有启用 ufw但如果你开了检查一下sudo ufw status如果Status: active执行sudo ufw allow 5432/tcp第四看容器端口映射是否正常docker port postgres应该输出5432/tcp - 0.0.0.0:5432。如果端口没映射出来回到 Compose 文件里检查ports配置。5.2 容器重启后数据“消失”了这个问题的场景往往是我用docker compose down再up -d发现之前建的库全没了。原因是数据目录没有正确挂载。如果你直接docker run postgres:16没有写-v /data/postgres/data:/var/lib/postgresql/data容器一旦被删除数据就随着容器匿名卷一起没了。即便写了挂载也要确认路径是否正确。检查方法docker inspect postgres | grep -A 5 Mounts看输出的Source是否是/data/postgres/dataDestination是否是/var/lib/postgresql/data。如果这两个值没问题数据就不会丢。另外提醒一句docker compose down默认不会删除命名卷但如果你用了匿名卷在down -v时会把卷删干净。所以要么坚持用宿主机目录挂载要么给卷起名字写清楚是postgres_data。我自己更偏爱宿主机目录挂载因为出问题后可以直接拿文件系统工具来排查。5.3 PostgreSQL 内存占用过高容器被 OOM 杀掉腾讯云小规格机器上PostgreSQL 跑着跑着就没响应看docker logs发现被系统杀了。这种情况常见于shared_buffers设置过大加上操作系统本身可用内存不足。我之前在一台 2G 内存的服务器上把shared_buffers调到 1G结果一跑并发查询内存就爆了。后来改成 256MB同时给系统留出 swap整个就稳了。如果你要调参数编辑 Compose 文件里的command段加上更多-c参数command: - postgres - -c - shared_buffers256MB - -c - effective_cache_size768MB - -c - work_mem16MB改完执行docker compose up -dPostgreSQL 是重启后才生效参数。这里要说明effective_cache_size不是真的分配内存只是给查询规划器一个“系统大概有多少缓存可用”的参考值设大了也不会被 OOM但会影响执行计划选择。5.4 时区差了 8 小时日志和查询时间全不对容器默认使用 UTC 时区所以数据库里的now()会和北京时间差 8 小时。第一次部署时我忘记配TZ业务方反馈数据时间不对排查了很久。解决办法是启动容器前就在 Compose 环境变量里加environment: TZ: Asia/Shanghai PGTZ: Asia/ShanghaiPGTZ会直接设置 PostgreSQL 的timezone参数。改完重启容器后在 psql 里执行SHOW timezone;确认输出是Asia/Shanghai时间就正常了。如果你已经启动过的容器没配这个变量可以在宿主机上修改 Compose 文件后重建容器。这里要注意重建容器不会删数据只要挂载卷和初始化目录没变。5.5 镜像拉取慢、中文乱码和编码问题镜像拉取慢的问题我前面提过可以配镜像加速。还有一个容易忽略的点是数据库编码。PostgreSQL 官方镜像默认使用UTF8作为编码这对中文存储没问题。但如果你是通过CREATE DATABASE appdb创建的库建议确认一下\l appdb看Collate和Ctype是否为C.UTF-8或en_US.UTF-8。只要编码是 UTF8中文字符基本不会乱码。实际遇到乱码多数是客户端连接时字符集设置不对确认客户端连接字符串里加了characterEncodingUTF8即可。如果你需要自定义排序规则可以在CREATE DATABASE时指定CREATE DATABASE appdb WITH ENCODING UTF8 LC_COLLATE C.UTF-8 LC_CTYPE C.UTF-8 TEMPLATE template0;模板要用template0因为template1的排序规则可能被默认设置限制住了。这些都是我在实际项目里踩过之后才记住的细节。5.6 我额外想提醒的小事容器日志如果一直输出password authentication failed先看是不是密码被改了但客户端还存着旧密码。PostgreSQL 不会因为 Docker 容器重启就重置密码除非你删了数据目录重新初始化。重新初始化是一个非常危险的操作会把所有数据清空千万小心。另外尽量别用latest标签固定镜像版本。生产环境必须指定一个明确的版本号比如postgres:16.4。这样以后镜像更新、团队协作时大家拿到的是同一个版本不会出现某天latest变了导致行为不一致的情况。容器时间长了日志文件会变大。PostgreSQL 的日志在容器内如果没做清理容器层会越来越大。建议在 Compose 里不要直接暴露日志驱动配置但可以在日常维护时定期docker logs --tail 100 postgres看一眼或者用docker system prune清理无用镜像和构建缓存。当然最重要的还是数据目录千万别被 Docker 的自动清理误伤所以一切手滑前先备份。6. 一点个人体会和部署建议这套“腾讯云 Ubuntu 24.04 Docker PostgreSQL”的组合我从测试环境一路用到生产环境最大的感受就是数据库本身不复杂复杂的是环境不一致带来的问题。容器化之后团队里任何人拿到的 PostgreSQL 环境都应该一模一样不会再出现“我本机能跑服务器上就报错”的尴尬。如果只让我挑一条最重要的建议我会说从一开始就把数据和配置分开数据目录挂载到宿主机备份计划提前配好。你不用追求一步到位把所有参数都调得多么极致但数据安全和可恢复性是底线。最后再分享一个小技巧每次更改 PostgreSQL 的配置或升级版本前我都会先手动执行一次备份把 dump 文件推到一个独立的地方比如腾讯云 COS 或者另一台机器。这样即使 Compose 文件写错、镜像拉取失败、甚至不小心清了容器手里永远有一份能恢复的筹码。数据库这种东西平时感觉不到它的存在丢一次数据就知道后悔了。希望这篇记录能让你少走一些我走过的弯路。