Docker Compose 生产安全加固:缩小服务暴露面
Compose 能稳定启动服务,不等于服务已经适合公网或生产环境。真正的安全边界来自可信镜像、最小端口、有效认证、受控权限、可审计日志和经过演练的恢复方案。
本文面向单机长期运行的 Compose 服务。高可用、跨主机调度和强租户隔离通常需要额外平台能力,不能通过增加几行 Compose 配置自动获得。
上线前判断
先确认服务是否具备生产所需的认证、权限模型、稳定版本、升级说明和安全维护记录。官方明确标记为演示、开发或 All-in-One 体验的部署,不应因为配置了 TLS 就改称生产方案。
固定镜像来源
镜像使用维护方明确发布的 registry 和版本 tag,避免长期跟随 latest。关键服务可以在验证后固定 digest,但仍要记录可读版本,便于判断发布说明和安全公告。
docker compose config --images
docker image inspect example/app:1.2.3 --format '{{json .RepoDigests}}'不要运行来源不明的镜像,也不要把“镜像能拉取”当作供应链可信证明。更新时重新核对维护者、tag、架构和配置兼容性。
缩小端口和网络暴露
只供同机代理访问的 HTTP 服务绑定回环地址:
services:
app:
image: example/app:1.2.3
ports:
- "127.0.0.1:8080:8080"数据库、缓存和内部 Worker 通常只加入 Compose 网络,不设置 ports。局域网服务应绑定明确网卡并通过防火墙限制来源;公网入口只开放代理需要的 80/443。将地址改成 0.0.0.0 不会自动提供认证、TLS 或访问控制。Docker Engine 早于 28.0.0 时,同一二层网络中的其他主机可能访问绑定在 localhost 的已发布端口;应升级 Engine 并从外部网络实际验证隔离效果。参见 Docker 端口发布说明。
管理凭据和密钥
示例密码不能进入正式环境。敏感值不要写在 Compose、镜像、命令行或版本库中;优先使用 Compose secrets、受限权限的环境文件或外部密钥系统。应用使用加密密钥保护数据库字段时,密钥必须与数据一起纳入恢复计划,但应分开存储。
chmod 600 .env
docker compose config --quietdocker compose config 可能展开环境变量,排障输出不能直接贴到公开 Issue 或聊天记录。
收紧容器权限
项目支持时使用非 root 用户、只读根文件系统、临时 tmpfs 和最少 capabilities。不要为了绕过权限问题直接使用 privileged: true、挂载整个宿主机根目录或执行 chmod 777。这些选项需要项目级兼容验证,不能机械加入所有 Compose。
挂载 /var/run/docker.sock 等价于向容器交出高权限 Docker 控制面。需要容器发现功能时,优先使用受限代理,并把管理界面限制在可信网络。
控制资源与日志
为服务设置与实际 Compose 实现兼容的 CPU、内存和进程限制,避免单个容器拖垮主机。日志使用轮转策略,防止磁盘被无限增长的 stdout/stderr 占满:
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"同时监控磁盘、容器重启次数、健康状态、证书期限和备份结果。只有日志没有告警,故障仍可能长期无人发现。
HTTPS 与源站隔离
公网服务使用反向代理终止 TLS,并让应用端口只接受代理访问。完整的 Caddy、Nginx、转发头和长连接配置见 Docker 服务反向代理与 HTTPS。应用只有在代理会清洗并重写 X-Forwarded-* 时才能信任这些请求头。
备份与更新
安全事件和错误更新都需要恢复能力。按 Docker 备份与恢复数据 建立异机副本,按 Docker Compose 更新、回滚与卸载服务 固定版本和回滚条件。备份文件本身包含用户数据和凭据时必须加密并限制访问。
安全验收
上线前检查实际监听地址、外部端口、匿名访问、管理入口、默认账号、密钥权限、镜像版本、容器权限、日志轮转和恢复记录。以下 app 换成当前项目的服务名:
docker compose ps
docker compose config --quiet
docker inspect "$(docker compose ps -q app)" --format '{{json .HostConfig.PortBindings}}'
docker inspect "$(docker compose ps -q app)" --format '{{json .HostConfig.Privileged}}'如果 docker compose ps -q app 为空,先检查服务名和启动状态,不要对空容器 ID 执行 inspect。再从非可信网络验证内部端口不能访问,从正常入口验证 TLS、登录、退出和权限拒绝行为。配置文件看起来正确不能替代网络侧验收。
安全边界
Rootless Docker 可以降低 daemon 与宿主机 root 权限绑定的风险,但不会修复应用漏洞、弱密码或错误的公网暴露。单机 Compose 也不自动提供多节点容灾、Web 应用防火墙、集中身份管理和合规审计;需要这些能力时应引入相应平台并重新评估架构。
常见问题
只绑定 127.0.0.1 后外部无法访问
这是预期结果。通过同机反向代理、VPN 或 SSH 隧道提供受控入口,不要直接改成全网卡监听来绕过设计。
容器改成非 root 后无法写入卷
核对镜像声明的 UID/GID 和宿主机目录属主,在测试环境修正明确目录权限。不要放宽整个数据树或宿主机目录。
日志轮转后仍然磁盘不足
继续检查应用自身日志、数据库、镜像、构建缓存和卷增长。Docker 日志限制只控制所选 logging driver 的文件。
加固完成后
把端口、账号、密钥、镜像、权限、日志、备份和更新负责人记录成可重复检查的上线清单。每次版本或网络入口变化后重新执行,而不是只在首次部署时检查一次。
总结
生产安全的重点不是堆叠配置,而是缩小真实暴露面并保留验证证据。可信镜像、回环源站、有效认证、最小权限、受控日志和可恢复数据共同构成单机 Compose 的安全基线。