恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
腾讯云Ubuntu 24.04上Docker部署PostgreSQL全流程指南
首页
资讯中心
/
腾讯云Ubuntu 24.04上Docker部署PostgreSQL全流程指南
腾讯云Ubuntu 24.04上Docker部署PostgreSQL全流程指南
发布时间:2026/9/16 8:17:26
腾讯云的 Ubuntu 24.04 服务器上跑数据库很多人第一反应就是直接 apt install postgresql然后在系统层面管理数据目录、配置文件、开机自启。这套传统流程在小规模场景下确实没毛病但一旦涉及版本升级、环境迁移、多机同步部署依赖系统的 PostgreSQL 会让人抓狂——版本是发行版锁死的数据目录散落在 /etc、/var/lib 下面还要维护 systemd 单元文件。我现在的习惯是凡是部署在云服务器上的 PostgreSQL一律 Docker 化除非业务对裸金属性能有变态级要求否则容器化带来的便利远超那点微乎其微的性能损耗。在腾讯云 Ubuntu 24.04 上走 Docker 部署 PostgreSQL 这条路我踩过不少坑也总结出一套从装 Docker 到数据备份的完整链路。这篇文章就把这套流程完整梳理一遍从环境准备、镜像加速、容器启动、安全组配置到备份恢复、问题排查全流程跑通适合刚接触云服务器 Docker 的开发者也适合想从传统部署迁移到容器化部署的运维朋友。1. 部署前的整体思路与架构设计1.1 为什么非要用 Docker 跑 PostgreSQL先解决一个核心问题既然 Ubuntu 的 apt 源里就有现成的 PostgreSQL为什么还要绕一圈用 Docker我用一个真实场景来解释。去年我在一台腾讯云服务器上部署了一个业务系统数据库用 apt 方式装了 PostgreSQL 14。半年后业务需要升级到 PostgreSQL 16系统源里没有直接可用的包只能手动添加 PostgreSQL 官方的 apt 源然后处理依赖冲突、迁移数据目录、逐个检查扩展兼容性折腾了整整一个下午。同期另一个项目直接用 Docker 部署升级只需两步改镜像 tag重启容器。Docker 方式还有几个硬核优势版本隔离一台服务器可以同时跑 PostgreSQL 14、15、16互不干扰用于版本对比测试极其方便。环境一致性本地开发用 Docker 跑 PostgreSQL 16生产环境也用同样的镜像基本杜绝了我本地没问题啊这类翻车事故。一键迁移数据目录挂在宿主机上容器随便删数据不丢换服务器时把数据目录和启动命令带过去就行。快速销毁重建配置错了直接删容器重新创建不用去清理 systemd 残留、配置文件碎片。1.2 腾讯云 Ubuntu 24.04 部署的架构模型这套部署方案整体采用最经典的宿主机直挂 Docker 容器架构不引入 Docker Compose、Kubernetes 这些编排工具在单机数据库场景下没必要上重武器。整个架构模型大概长这样腾讯云 CVM 运行 Ubuntu 24.04 LTS宿主机上只装 Docker Engine 和 Docker Compose Plugin备用不跑其他占用资源的服务。PostgreSQL 容器通过网络端口 5432 映射到宿主机 0.0.0.0:5432供外部应用访问。PostgreSQL 的数据目录、配置文件目录、备份目录全部通过 bind mount 方式挂载到宿主机指定路径实现数据和容器生命周期解耦。容器设置--restart always服务器重启后容器自动拉起避免业务停机。腾讯云安全组和 Ubuntu 自带的 UFW 防火墙双重管控端口访问范围数据库不裸奔到公网。有人会问既然有 Docker 的 volume 机制为什么选择 bind mount 而不是 named volume我的理由是 bind mount 把数据路径显式暴露出来比如/data/postgresql/data后续备份、迁移、排查问题时直接进入这个路径操作路径明确、心智负担低。而 named volume 的存储位置在/var/lib/docker/volumes/下面找起来多一层绕路。1.3 部署前的关键决策点部署前有几个决定会影响后续使用体验建议在一开始就定下来。第一个是 PostgreSQL 版本。当前最新稳定版是 17但我个人建议在腾讯云 Ubuntu 24.04 上部署时优先选择 16不是最新的不好而是 PostgreSQL 16 经历了大量生产环境验证各种第三方工具、驱动兼容性最成熟。如果你有特殊需求需要 17直接用官方镜像的pgvector/postgres:16、postgres:17这类 tag 就行部署流程完全一致。第二个是数据盘规划。腾讯云的系统盘默认 50GB如果 PostgreSQL 要存储大量业务数据强烈建议单独挂载一块数据盘把数据目录放到数据盘上。系统盘坏了数据盘还在这对数据库来说是很重要的容灾保障。挂载数据盘后将数据盘格式化为 ext4 文件系统挂载到/data目录后续 PostgreSQL 数据全部放这里面。第三个是内存和连接数规划。Ubuntu 24.04 服务器的内存越大越好PostgreSQL 不是省内存的家伙。如果服务器内存只有 2GBPostgreSQL 默认配置下的shared_buffers只有 128MBeffective_cache_size也只有 4GB这些参数需要结合实际内存调整。容器启动时可以通过--shm-size参数扩大/dev/shm大小避免并行查询时临时文件溢出。2. 腾讯云 Ubuntu 24.04 环境准备与 Docker 安装2.1 系统基础配置与镜像加速拿到一台全新的腾讯云 Ubuntu 24.04 服务器后不要急着装 Docker先把系统基础环境收拾干净。用 SSH 登录服务器后第一步是更新系统软件包sudo apt update sudo apt upgrade -yUbuntu 24.04 刚发布时我遇到过一个问题如果系统是 pubcloud 镜像apt update时可能因为软件源指向了内网镜像源而报错。解决办法是把/etc/apt/sources.list.d/ubuntu.sources里的源地址改为腾讯云内网镜像或者阿里云镜像。腾讯云内网镜像地址一般是mirrors.tencentyun.com但注意内网镜像只在腾讯云 CVM 内网能访问换到别的环境就失效了。第二步是安装基础工具比如curl、wget、vim、ca-certificates、gnupg这些后续配置 Docker 源和操作文件时都能用上sudo apt install -y curl wget vim ca-certificates gnupg lsb-release第三步是配置 Docker 镜像加速器。这一步在国内环境部署必须做因为 Docker Hub 的镜像拉取速度非常不稳定直接 pull 一个几百 MB 的 PostgreSQL 镜像可能耗时十几分钟甚至超时。腾讯云容器服务提供过内网镜像加速器地址格式类似https://mirror.ccs.tencentyun.com配置方式很简单在/etc/docker/daemon.json文件中添加 registry-mirrors 字段sudo mkdir -p /etc/docker cat EOF | sudo tee /etc/docker/daemon.json { registry-mirrors: [https://mirror.ccs.tencentyun.com] } EOF配置加速器后需要重启 Docker 才能生效。注意加速器只对 Docker Hub 官方镜像生效对于pgvector/pgvector这类第三方仓库镜像加速效果有限不过 PostgreSQL 官方镜像都是走 Docker Hub 的所以影响不大。2.2 在 Ubuntu 24.04 上安装 Docker 的正确姿势Ubuntu 24.04 上装 Docker 有两条主流路线用官方一键脚本或者手动配置 apt 源安装。我推荐用官方一键脚本省事且不容易出错curl -fsSL https://get.docker.com | bash -s docker这条命令会自动检测 Ubuntu 24.04 的架构和版本配置好 Docker 官方 apt 源并安装 Docker Engine、containerd、Docker CLI 等全部组件。装完后执行sudo systemctl enable --now docker sudo systemctl status docker如果状态显示active (running)说明 Docker 安装成功。执行sudo docker version可以确认客户端和服务端版本输出里包含 Server 部分的内容说明 Docker 守护进程正常。还有一条手动安装路线适合对安装过程有洁癖或者需要精确控制版本的同学# 添加 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 apt 源 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 sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin手动安装有一个坑要注意Ubuntu 24.04 的代号是noble但 Docker 官方源里对应的是noble如果apt update时报了 404 错误说明 Docker 官方源还没有更新到这个版本需要手动把$(. /etc/os-release echo $VERSION_CODENAME)替换成jammyUbuntu 22.04 的代号大部分情况下不会出现问题但我不建议这么操作。用官方脚本就没这个烦恼所以如果只是普通部署直接跑一键脚本最省心。2.3 验证 Docker 环境是否可用Docker 装好后不要急着拉 PostgreSQL 镜像先做两个验证动作。第一个验证是跑一个 hello-world 容器sudo docker run --rm hello-world如果输出Hello from Docker!说明 Docker 能正常拉取镜像并启动容器。这一步能同时验证镜像加速器是否生效如果拉取 hello-world 都要等很久说明加速器配置有问题需要检查/etc/docker/daemon.json的格式。第二个验证是检查 Docker 存储驱动。docker info命令输出里找到Storage Driver这一项正常情况下是overlay2。如果显示的是vfs或者aufs说明存储驱动配置有问题数据存储效率和容器性能都会受影响。Ubuntu 24.04 的默认内核基本都支持 overlay2大概率不会遇到这个坑但检查一下总归放心。另外一个比较实用的操作是把当前用户加入 docker 组这样不用每次执行 docker 命令都要加 sudosudo usermod -aG docker $USER newgrp docker加完组后执行docker ps试试如果还提示权限不足建议重新登录一次 SSH 会话让用户组变更生效。3. PostgreSQL 容器部署核心步骤与参数详解3.1 获取 PostgreSQL 镜像并确认版本Docker 环境就绪后开始部署 PostgreSQL。先拉取官方镜像docker pull postgres:16这里说说版本选择的讲究。Docker Hub 上 postgres 官方镜像的标签可以说是五花八门postgres:latest当前最新稳定版目前是 17.x但 tag 是变动的不推荐生产环境使用。postgres:1616 系列的最新小版本比如 16.4适合部署主力数据库。postgres:16.4-bookworm指定 Debian 基础镜像版本适合对基础系统有硬性要求的场景。postgres:16-bullseyeDebian 11 为基础镜像镜像体积稍小但底层库较旧。postgres:16-alpine基于 Alpine Linux镜像体积最小约 80MB但 glibc 换成 musl某些扩展可能编译不了非必要不建议生产使用。我的建议是首次部署用postgres:16拉取当前 16 系列最新版本后续如果需要精确固定版本再用docker tag把镜像固定到具体的 16.x 版本号。镜像拉取完后执行docker images | grep postgres查看本地镜像信息确认镜像已经就位。3.2 创建数据目录并规划挂载路径PostgreSQL 容器不能裸奔数据必须落在宿主机上。我在腾讯云服务器上的路径规划如下# 数据盘挂载目录如果有单独数据盘 sudo mkdir -p /data/postgresql # 数据目录存放 PostgreSQL 数据文件 sudo mkdir -p /data/postgresql/data # 备份目录存放逻辑备份文件 sudo mkdir -p /data/postgresql/backup # 自定义配置目录存放自定义 postgresql.conf、pg_hba.conf 等 sudo mkdir -p /data/postgresql/conf然后设置权限PostgreSQL 容器内默认以postgres用户UID 999运行所以宿主机上的数据目录必须对 UID 999 可写否则容器启动时会报权限错误。我直接给/data/postgresql分配一个宽松的权限简单粗暴sudo chown -R 999:999 /data/postgresql这里有个细节要注意chown的目标用户不是postgres这个名字而是 UID 999。因为在容器内部postgres用户的 UID 就是 999宿主机上即便没有这个用户名只要 UID 对得上容器就能正常读写。如果你用chown postgres:postgres而宿主机上没有这个用户会直接报错。如果你觉得数据盘不放心只挂了一个系统盘那就在/var/lib/postgresql下创建目录路径随你喜欢但挂载的数据卷路径必须明确记录后续做备份全靠它。3.3 启动 PostgreSQL 容器的完整命令与参数解析执行下面的命令启动 PostgreSQL 容器docker run -d \ --name postgres \ --restart always \ --shm-size256m \ -p 5432:5432 \ -e POSTGRES_USERadmin \ -e POSTGRES_PASSWORDYourStrongPssw0rd \ -e POSTGRES_DBmyapp \ -e TZAsia/Shanghai \ -v /data/postgresql/data:/var/lib/postgresql/data \ -v /data/postgresql/conf:/etc/postgresql/conf \ -v /etc/localtime:/etc/localtime:ro \ postgres:16逐项拆解一下参数-d后台运行容器终端不阻塞。--name postgres容器命名后续docker stop postgres、docker logs postgres都用这个名字。--restart always容器崩溃或服务器重启后自动恢复这是生产部署的标配参数不加这个大概率会在服务器重启后手动去拉容器。--shm-size256m扩大/dev/shm大小PostgreSQL 并行执行查询时会在共享内存中缓存一些数据默认 64MB 太小并行查询一多就可能报could not resize shared memory错误。256MB 是一个经验值内存充足的可以设 512MB。-p 5432:5432端口映射宿主机 5432 端口转发到容器的 5432 端口。如果宿主机已经有服务占用 5432 端口可以改成-p 5433:5432但应用连接地址也要同步修改。-e POSTGRES_USERadmin初始化时创建的超级用户名。注意这个环境变量只在数据目录为空时生效如果数据目录已有初始化数据这个变量会被忽略。所以首次创建时一定要定好用户名后期想改超级用户名非常麻烦。-e POSTGRES_PASSWORD...超级用户的密码。密码尽量复杂至少 16 位包含大小写字母、数字和特殊字符。这个密码会写入数据库但如果你用docker inspect查看容器配置密码是明文可见的所以别在多人共享的服务器上把密码写进启动命令历史里。-e POSTGRES_DBmyapp初始化时额外创建的一个数据库。如果不设置这个变量默认只创建一个和 POSTGRES_USER 同名的数据库。业务数据库建议显式创建避免后续再用createdb去建。-e TZAsia/Shanghai设置容器时区。不加这个参数容器内默认 UTC 时区PostgreSQL 的now()函数返回的时间会跟北京时间差 8 小时排查问题时很郁闷。-v /data/postgresql/data:/var/lib/postgresql/data把宿主机的数据目录挂载到容器内的数据目录。这是整个命令里最重要的一条数据持久化全靠它。-v /data/postgresql/conf:/etc/postgresql/conf挂载自定义配置目录。PostgreSQL 官方镜像默认不会读取这个目录下的配置需要额外指定-c config_file/etc/postgresql/conf/postgresql.conf这个我在下文会专门讲。-v /etc/localtime:/etc/localtime:ro把宿主机的时区文件挂载进容器保证容器内系统时间和宿主机一致。3.4 容器启动后的初始化检查容器启动后不要急着连接数据库先做几项检查。第一项查看容器运行状态docker ps输出里STATUS列显示Up X minutes或者Up X hours说明容器正常运行如果显示Exited (1)或者Restarting说明启动出问题了。第二项查看容器日志docker logs postgres正常启动时日志末尾会有database system is ready to accept connections的提示。如果看到FATAL: data directory ... has invalid permissions说明数据目录权限不对如果看到FATAL: could not write lock file ... Permission denied多半是数据目录的属主不是 UID 999。第三项进入容器内验证 PostgreSQL 版本docker exec -it postgres psql -U admin -d myapp -c SELECT version();输出正常说明数据库服务已经可用可以开始配置远程连接了。4. 腾讯云安全组与外部连接配置4.1 腾讯云安全组放行 PostgreSQL 端口容器内部数据库启动后默认监听0.0.0.0:5432宿主机端口也映射好了但外部应用要连上这台腾讯云服务器上的 PostgreSQL还必须过安全组这一关。腾讯云的安全组相当于云服务器最外层的防火墙在服务器控制台的防火墙之前生效。如果安全组没有放行 5432 端口无论服务器内部如何配置外部永远无法连接。登录腾讯云控制台进入云服务器实例详情页找到安全组标签页点击配置规则添加入站规则类型自定义来源建议指定 IP 地址或 IP 段而不是 0.0.0.0/0协议端口TCP:5432策略允许来源这里我要多说一句。很多教程直接教人放行 0.0.0.0/0也就是让所有公网 IP 都能访问 5432 端口。这对数据库来说风险很大——PostgreSQL 的超级用户密码即使再复杂也扛不住暴力破解工具的持续探测如果 PostgreSQL 版本存在漏洞裸露到公网等于给自己埋雷。正确的做法是先只放行自己当前所在的公网 IP比如家里的宽带 IP 或公司的固定公网 IP。后续如果数据库需要被多个应用访问再把来源缩小到这些应用的公网 IP 或者负载均衡器地址。如果确实需要从任意 IP 访问比如云函数、临时测试环境也建议不要直接放行 0.0.0.0/0 加 5432 端口而是使用腾讯云的数据库安全组特性或者在服务器上配置 fail2ban 这类防暴力破解工具。4.2 Ubuntu 防火墙 UFW 配置腾讯云安全组是云平台层面的限制Ubuntu 系统自带的 UFW 是操作系统层面的防火墙。安全组已经放行的情况下理论上可以不开启 UFW直接依赖安全组管控。但我个人的习惯是双重保险服务器上 UFW 默认关闭仅靠安全组管控如果你所在的安全基线要求开启 UFW可以参考如下配置# 允许 SSH sudo ufw allow OpenSSH # 允许 PostgreSQL 端口限制来源 IP sudo ufw allow from 你的公网IP to any port 5432 proto tcp # 启用防火墙 sudo ufw enable # 查看状态 sudo ufw status verbose注意顺序很重要。先放行 SSH 再 enable否则一旦防火墙把 SSH 也拦了你就要去腾讯云控制台用 VNC 登录服务器救火了非常狼狈。如果你开启了 UFW 但没有放行 Docker 的端口会发现 Docker 容器端口映射到宿主机后外部依然无法访问。这是因为 Docker 的 iptables 规则和 UFW 的规则存在交互特别容易踩坑。最简单的处理方式就是在 UFW 中显式放行 5432 端口然后检查一下规则生效情况。4.3 PostgreSQL 远程连接配置PostgreSQL 默认配置只监听本地回环地址远程连接需要修改监听配置。但 Docker 容器有一个特性通过-p映射端口后容器内部的端口总是绑定在 0.0.0.0:5432只要容器内 PostgreSQL 配置正确监听所有地址外部流量就能进来。如果容器启动时没有指定-c listen_addresses*参数且容器内默认的 postgresql.conf 里listen_addresses为localhost远程连接会失败。官方镜像的默认配置中listen_addresses为*也就是监听所有网卡地址所以大概率不会踩这个坑。真正容易出问题的是pg_hba.conf认证配置。官方镜像生成的pg_hba.conf默认允许来自任意主机的密码认证连接host all all 0.0.0.0/0 scram-sha-256这意味着只要网络能通、密码正确任何 IP 都可以连接。这再次说明了安全组和防火墙管控来源 IP 的重要性——密码认证只解决了你是谁的问题并没有解决你从哪里来的问题。4.4 远程连接实测与常见连接失败原因外部应用连接 PostgreSQL 时最常用的工具是psql命令行或者各种编程语言驱动。在本地电脑上测试连接psql -h 你的服务器公网IP -p 5432 -U admin -d myapp -W输入密码后能正常进入 psql 交互界面说明外部连接链路已经全部打通。如果连接超时或者连接被拒绝从以下几个方向排查容器本身是否正常运行docker ps查看容器状态。端口映射是否生效在服务器上执行ss -tlnp | grep 5432看到0.0.0.0:5432说明 Docker 端口映射正常。安全组是否放行腾讯云控制台检查入站规则。UFW 是否拦截sudo ufw status查看规则。PostgreSQL 监听地址是否正确docker exec -it postgres psql -U admin -c SHOW listen_addresses;输出*才正常。上述链路逐级排查即可定位问题。实际中最多的情况是安全组没放行其次是 UFW 拦截真正因为 PostgreSQL 配置导致的远程连接失败反而少见。5. 数据持久化、备份恢复与容器管理5.1 数据持久化的原理与常见误区前面启动命令里的-v /data/postgresql/data:/var/lib/postgresql/data就是数据持久化的关键。PostgreSQL 的数据文件、WAL 日志、事务日志都会写入这个目录容器删除重建后只要挂载相同目录数据就完好无损。但我在实操中发现很多人对持久化存在两个误解。误区一.env文件或者docker-compose.yml里的配置能自动应用持久化。实际上持久化只与数据目录绑定有关容器重建后-e POSTGRES_PASSWORD这类环境变量会被忽略因为它只影响数据目录初始化阶段。也就是说你不能期望通过修改POSTGRES_PASSWORD来修改已有数据库的超级用户密码。误区二把docker commit提交容器快照当作持久化方案。如果你的数据目录没有挂载到宿主机而是写在容器可写层里那么docker commit确实能生成一个包含数据的镜像但这个镜像可能包含密码等敏感信息而且后续维护麻烦。千万别用这种方式做持久化老老实实挂载数据目录。5.2 PostgreSQL 逻辑备份与恢复实操PostgreSQL 的数据备份有两种主流方式逻辑备份pg_dump/pg_restore和物理备份pg_basebackup或文件系统级快照。单机部署场景下逻辑备份足够应对绝大多数需求操作简单、可移植性强。使用 Docker 执行逻辑备份特别方便直接调用容器内的pg_dump工具# 备份单个数据库自定义格式 docker exec -it postgres pg_dump -U admin -d myapp -F c -f /tmp/myapp.dump # 将备份文件从容器内拷贝到宿主机 docker cp postgres:/tmp/myapp.dump /data/postgresql/backup/但更好的做法是直接把备份文件写到宿主机挂载目录省去docker cp这一步。因为我们已经挂了/data/postgresql/backup到容器内但是官方镜像没有默认映射这个路径所以要加启动参数或者用 exec 进去配合宿主机路径。可以这样操作把备份目录挂载到容器的/backup路径下但这需要在容器创建时就设置好。如果在现有容器上临时备份直接docker cp就行。下面是一个标准备份脚本我一般放在/usr/local/bin/pg-backup.sh配合 crontab 定时执行#!/bin/bash # PostgreSQL 容器逻辑备份脚本 BACKUP_DIR/data/postgresql/backup DATE$(date %Y%m%d_%H%M%S) DB_NAMEmyapp DB_USERadmin CONTAINER_NAMEpostgres # 保留最近 7 天的备份 find $BACKUP_DIR -name *.dump -mtime 7 -delete # 执行备份 docker exec $CONTAINER_NAME pg_dump -U $DB_USER -d $DB_NAME -F c -f /tmp/${DB_NAME}_${DATE}.dump # 拷贝备份文件到宿主机 docker cp $CONTAINER_NAME:/tmp/${DB_NAME}_${DATE}.dump $BACKUP_DIR/ # 清理容器内临时文件 docker exec $CONTAINER_NAME rm -f /tmp/${DB_NAME}_${DATE}.dump echo [$(date %Y-%m-%d %H:%M:%S)] Backup completed: ${DB_NAME}_${DATE}.dump加入 crontab 定时执行crontab -e # 每天凌晨 2 点执行备份 0 2 * * * /usr/local/bin/pg-backup.sh /var/log/pg-backup.log 21恢复备份时先创建目标数据库再使用pg_restore恢复# 创建目标数据库 docker exec -it postgres createdb -U admin -T template0 restore_db # 恢复备份 docker exec -it postgres pg_restore -U admin -d restore_db /tmp/myapp.dump恢复时加上-T template0是因为默认的 template1 可能带有业务相关的对象而 template0 是纯净模板能避免恢复时对象冲突。5.3 容器管理日常操作速查掌握了部署和备份日常管理还有一些高频操作。下表整理了我最常用到的 Docker 管理命令操作场景命令查看容器日志docker logs -f postgres进入容器内 bashdocker exec -it postgres bash进入 psql 交互界面docker exec -it postgres psql -U admin -d myapp停止容器docker stop postgres启动容器docker start postgres重启容器docker restart postgres删除容器不删数据docker rm -f postgres查看容器资源占用docker stats postgres查看端口映射docker port postgres查看挂载信息docker inspect postgres | grep -A 5 Mounts在日常运维中docker logs -f postgres是排查问题最有力的工具PostgreSQL 的每次连接、每条错误日志都会输出到标准输出通过docker logs直接查看比进入容器翻日志文件高效得多。5.4 使用 Docker Compose 管理 PostgreSQL可选如果部署的环境里不止有 PostgreSQL还涉及 Redis、Nginx 等其他组件用 Docker Compose 统一管理会更方便。在这里提供一个 PostgreSQL 的 compose 配置示例version: 3.8 services: postgres: image: postgres:16 container_name: postgres restart: always shm_size: 256m environment: POSTGRES_USER: admin POSTGRES_PASSWORD: YourStrongPssw0rd POSTGRES_DB: myapp TZ: Asia/Shanghai ports: - 5432:5432 volumes: - /data/postgresql/data:/var/lib/postgresql/data - /etc/localtime:/etc/localtime:ro使用方式docker compose up -ddocker compose down会停止容器并移除容器和网络但不会删除数据卷所以数据还是安全的。5.5 时区与日志时区细节数据库部署中时区问题经常被忽视却是真真切切影响业务的问题。前面说了容器里设置了TZAsia/Shanghai这保证 PostgreSQL 的now()函数返回的是北京时间。但还有两个细节第一PostgreSQL 默认日志时间戳用的是系统时区还是 UTC这取决于log_timezone配置。可以通过 SQL 查询SHOW TimeZone; SHOW log_timezone;正常情况下两条都显示Asia/Shanghai。如果TimeZone显示Etc/UTC说明TZ环境变量没有生效或者容器启动时没有加上这个参数。重新创建容器时加-e TZAsia/Shanghai即可。第二挂在宿主机上的数据目录里的日志文件如果log_timezone是 UTC那么日志文件里记录的时间戳和业务时间相差 8 小时排查问题时看日志容易错位。所以在初始化后立即检查这两个参数一劳永逸。6. 实际部署中的问题排查与经验总结6.1 容器启动报错排查速查表下面是我在实际部署和帮助别人排查时总结的常见问题速查表几乎覆盖了腾讯云 Ubuntu 24.04 上部署 PostgreSQL 的绝大部分坑现象原因解决方案docker: Error response from daemon: conflict...同名容器已存在docker rm -f postgres后重新创建FATAL: data directory /var/lib/postgresql/data has invalid permissions数据目录属主不是 UID 999sudo chown -R 999:999 /data/postgresql/datachmod: changing permissions of /var/lib/postgresql/data: Operation not permitted数据目录在挂载的只读卷上检查/etc/fstab挂载参数去掉 rocould not translate host name ... to address连接串主机地址不对检查应用配置中的数据库地址是否为公网 IP 或内网 IPconnection refused端口未映射或防火墙拦截ss -tlnp查看监听安全组和 UFW 逐一排查password authentication failed密码错误或 pg_hba.conf 认证方式不匹配重置密码ALTER USER admin WITH PASSWORD 新密码;FATAL: no pg_hba.conf entry for host ...pg_hba.conf 未放行来源 IP修改 pg_hba.conf 或使用容器默认的全允许配置could not resize shared memory ... No space left on device/dev/shm 太小容器启动加--shm-size256minvalid value for parameter TimeZone: Asia/Shanghai容器内时区数据不完整挂载/etc/localtime或安装 tzdataERROR: permission denied to create extension非超级用户创建扩展使用超级用户 admin 创建扩展PANIC: could not write to file pg_xlog/...数据目录所在磁盘空间不足df -h检查磁盘容量清理或扩容6.2 我踩过的一个“经典”坑数据目录权限问题把这个坑单独拿出来说是因为它是我在腾讯云 Ubuntu 24.04 上部署 PostgreSQL 时第一个遇到的而且报错信息非常具有迷惑性。当时我已经用sudo mkdir -p创建了/data/postgresql/data直接启动容器结果容器启动失败日志输出如下chmod: changing permissions of /var/lib/postgresql/data: Operation not permitted我第一反应是 Docker 权限问题网上查了一圈有人说是 SELinux 问题有人说挂载方式不对。排查了快半个小时才意识到这个错误根本不是在修改权限而是因为宿主机对/data/postgresql/data是 root 所有容器内 postgres 用户UID 999对它的父目录没有写入权限导致初始化脚本无法执行操作。解决办法很简单把目录属主改成 UID 999sudo chown -R 999:999 /data/postgresql/data sudo chmod 700 /data/postgresql/data但是要注意一个更隐蔽的坑如果/data/postgresql/data所在的父目录/data或/data/postgresql的写入权限有问题即使顶层目录权限对了容器照样起不来。所以稳妥做法是确保整个路径链上的目录都允许 UID 999 访问sudo chown -R 999:999 /data/postgresql这个教训就是Docker 挂载目录的权限问题不能只看最终目标目录要检查路径上每一层目录的权限。6.3 密码修改与安全加固实操容器部署的 PostgreSQL 如何修改密码网上很多教程说直接改环境变量重建容器这在数据目录已初始化的前提下是不生效的。正确姿势是在 psql 里执行 SQL 重置密码docker exec -it postgres psql -U admin -d myapp -c ALTER USER admin WITH PASSWORD 新密码;如果你忘记了超级用户密码也有办法绕过。修改pg_hba.conf临时改为 trust 认证重启容器后免密进入重置密码后再改回去。具体操作停止容器docker stop postgres修改宿主机挂载目录下的pg_hba.conf在/data/postgresql/data/pg_hba.conf中将scram-sha-256临时改为trust启动容器docker start postgres免密进入 psql 重置密码恢复pg_hba.conf配置重启容器这个方法在单机部署场景下很实用但操作时要小心避免把pg_hba.conf改坏。改之前最好先备份原文件。安全加固层面除了前面说的控制安全组来源 IP、设置强密码还可以在 PostgreSQL 侧做一些配置禁止超级用户远程登录修改pg_hba.conf中超级用户记录为local认证禁止host方式。创建单独的业务账号只授予业务数据库的必要权限日常应用连接使用业务账号而不是超级用户 admin。开启 SSL 连接PostgreSQL 16 支持 SSL通过挂载 SSL 证书并设置ssl on客户端连接时使用 SSL 加密链路。定期收集 pg_stat_activity 检查活跃连接及时发现异常来源。6.4 性能调优的几个简单参数Docker 部署的 PostgreSQL 默认配置比较保守按腾讯云服务器的实际配置调几个关键参数对性能提升特别明显。先看一下当前配置docker exec -it postgres psql -U admin -d myapp -c SHOW shared_buffers; SHOW effective_cache_size; SHOW work_mem; SHOW maintenance_work_mem;以一台 4 核 8GB 内存的腾讯云 CVM 为例建议的调整参数参数默认值建议值说明shared_buffers128MB2GB共享缓冲区通常设置为内存的 25%effective_cache_size4GB6GB操作系统缓存估算值通常为内存的 75%work_mem4MB16MB排序、哈希操作内存上限按需调大maintenance_work_mem64MB256MB维护操作如 VACUUM内存调大加快维护max_connections100200按业务预估连接数调整checkpoint_completion_target0.50.9减少检查点 I/O 高峰wal_buffers16MB64MBWAL 缓冲区适当调大提高写入性能修改这些参数有两种方式。一种是编辑宿主机挂载的postgresql.conf文件然后重启容器另一种是使用ALTER SYSTEM命令在线修改ALTER SYSTEM SET shared_buffers 2GB; ALTER SYSTEM SET effective_cache_size 6GB; SELECT pg_reload_conf();ALTER SYSTEM方式修改会写入postgresql.auto.conf文件重启容器后依然生效而且不需要手动编辑文件更安全便捷。修改后执行pg_reload_conf()可以即时生效不需要重启容器。但要注意shared_buffers需要重启数据库才能完全生效pg_reload_conf()只能加载一部分参数。修改完核心参数后稳妥做法还是重启容器。6.5 在腾讯云环境下的额外建议部署在腾讯云上有几个和腾讯云环境强相关的点单独拿出来说。第一如果服务器使用的是默认 VPC 网络其他腾讯云产品比如云函数、TKE 集群访问数据库时走的是内网地址。内网地址不受安全组公网规则限制而是受 VPC 内安全组规则限制需要单独配置允许内网来源访问 5432 端口。这一点经常被忽略公网通了内网反而不通。第二腾讯云服务器支持快照备份这是最省事的数据容灾方案。登录控制台在实例详情页找到快照功能可以对整个系统盘或数据盘创建快照。创建快照后再结合 PostgreSQL 逻辑备份形成物理快照 逻辑备份双重保险。物理快照恢复极快逻辑备份可精细恢复单个数据库或表。第三Ubuntu 24.04 的服务器可以加装腾讯云监控 Agent在控制台上查看 CPU、内存、磁盘 IO 指标配合 Docker 的docker stats postgres命令可以比较全面地掌握数据库服务器的资源使用情况提前发现磁盘空间不足、内存溢出等隐患。写在最后的实操体会我在腾讯云 Ubuntu 24.04 上通过 Docker 部署 PostgreSQL 已经跑了一年多整体体验非常稳定。最直观的感受是容器化部署让我把环境差异、依赖冲突这些琐碎问题全部隔离掉了数据库出错时能快速通过重启容器或者查看日志来定位问题而不是陷入操作系统包管理的泥潭。如果让我给后来者一个最重要的建议那就是数据备份不要等到出问题才想起做从部署完成的第一天起就把自动备份脚本配置好同时定期做一次恢复演练——我们把备份文件恢复到临时数据库里全流程跑通这样才叫真正的备份而不是一堆躺在磁盘上没人管的数据文件。另外一点值得分享的是Docker 部署 PostgreSQL 的学习成本并不高核心就是把启动命令里的参数搞清楚、数据目录挂载对、安全组端口放行对这三板斧在手部署任何一台新服务器都能轻松上手。后续如果业务规模变大也可以平滑迁移到 RDS 托管数据库或者容器集群架构演进空间比传统部署模式要灵活得多。