
发布时间:2026-10-04 21:12:36
腾讯云服务器 Docker 部署实战:镜像、compose 与容器日志
正文
我见过最典型的一次翻车,是客户把一个跑了半年的数据库容器重启了一下,数据全没了——因为他一直把数据写在容器层里,docker rm 之后那层就跟着消失了。所以先给结论:腾讯云服务器 Docker 部署,排在第一位的不是怎么装、怎么起,而是想清楚哪份数据必须离开容器。 装 Docker 半小时的事,数据丢了可能是一个季度的业务。
容器本身是"用完即弃"的设计,这个理念放在无状态服务上很优雅,放在有状态的数据上就是灾难。这篇我把 Docker 在 CVM 上的落地顺序拆开讲:镜像源怎么配、数据卷怎么挂、compose 怎么编排、资源怎么限、日志怎么收,以及轻量应用服务器上跑容器的那条内存红线到底在哪。
先装对 Docker:源、镜像加速与一个反直觉提醒
Linux 上装 Docker 现在很顺,Ubuntu 系一条 apt install docker.io 或者走官方脚本,RHEL/TencentOS 用 yum install docker 都能起来。但国内环境有个绕不开的点:拉镜像慢。解决办法是配镜像加速器,在 /etc/docker/daemon.json 里写 registry-mirrors,然后 systemctl restart docker 生效。加速器地址会变,用之前最好确认当年可用的源,别照抄几年前的博客。
一个反直觉的提醒:别急着追最新版,也别用 `curl | bash` 这种一把梭脚本在生产机上裸跑。 Docker 的版本和内核特性绑定,某些较新的特性需要较新内核;而生产环境更该看重的是可重复、可控。我一般建议固定一个大版本,用包管理器装,方便后续统一升级和回滚。腾讯云 CVM 的 TencentOS Server、OpenCloudOS 这类系统对容器支持都比较完整,选镜像时留意 x86_64 和 aarch64 的架构区别——ARM 实例上拉 x86 镜像会直接报 exec format error,需要选择多架构 manifest 的镜像。
装完记得把常用运维用户加进 docker 组,否则每条命令都要 sudo。但也要知道,进 docker 组约等于拿到 root——因为容器可以挂宿主机根目录,这一点在做权限管理时要心里有数。
数据别放容器层:数据卷持久化的正确姿势
回到开头那个事故。容器的可写层随容器生命周期存在,容器一删,层就没了,镜像更新重建更是连痕迹都不留。所以凡是需要留下来的东西——数据库文件、上传的附件、证书、配置,都必须落在容器之外。
Docker 有两种持久化方式:数据卷(volume,由 Docker 管理,存在 /var/lib/docker/volumes)和绑定挂载(bind mount,直接挂宿主机目录)。数据卷更适合纯 Docker 场景,迁移和备份由 Docker 统一处理;绑定挂载更直观,适合你想直接看文件、或用别的方式备份的目录。我的习惯是:数据库和需要精细备份的目录用绑定挂载到一块独立的 CBS 云硬盘上,应用日志和数据卷用 volume。这样备份策略可以跟着云硬盘的快照走,异地和跨区复制也能复用同一套机制。
还得提醒一句:别把宿主机上正在被其他服务使用的目录,直接绑进容器里乱写。 我见过把宿主机 /etc 挂进容器结果把系统配置改乱的案例。容器内外的文件属主和权限映射(UID/GID)也容易出问题,映射不对会导致文件写入失败或权限混乱,多用户环境下尤其要留意。
compose 编排多服务:一份文件代替一堆命令
单容器用 docker run 还行,一旦是"Web + 数据库 + 缓存"这种多服务组合,docker run 就会变成一长串没人记得住的参数。这时候上 docker compose,把服务、网络、卷、环境变量写进一份 compose.yaml,一条 docker compose up -d 起全套,down 收全套,logs 看全套。
compose 里我会固定写几样东西:restart: unless-stopped 让服务跟随宿主机重启,避免机器维护后忘了拉起来;depends_on 表达启动顺序(注意它只保证启动次序,不保证依赖服务真的就绪,应用侧还是要有重试);环境变量和密钥尽量用 env_file 或外部注入,别硬编码在文件里;数据卷按上一节的原则挂好。多服务之间用 compose 自动创建的内部网络互访,容器名就是主机名,比记 IP 稳定得多。
生产上我建议把 compose.yaml 和相关的环境文件放进代码仓库,版本化管理。这样换机器、扩节点时,拉代码加一条命令就能复现环境,这才是容器化真正省事的地方。
资源限制:别让一个容器把宿主机拖垮
容器默认可以吃满宿主机的 CPU 和内存,这是很多故障的根因:一个内存泄漏的应用容器慢慢膨胀,最后触发内核的 OOM Killer,把宿主机上别的进程连同容器一起干掉,甚至宿主机自己无响应。在云服务器上跑多个容器,不做资源限制等于把整台机器的稳定性交给了最不守规矩的那个容器。
做法很直接:docker run 加 --memory 512m --cpus 1.5,compose 里用 deploy.resources.limits 或者兼容写法声明。内存限制之外,--memory-swap 能限制可用的交换空间,防止容器靠 swap 硬撑导致整机 IO 被拖死。CPU 限制用的是配额和权重,能约束上限但不会钉死,属于软性约束。
这里要区分一个概念:容器的资源限制底层是 cgroup。限制设得太紧,应用可能因为拿不到内存被 OOM Killer 干掉;设得太松又失去保护意义。我一般先观察应用的真实内存曲线,再在峰值之上留一段余量来设限制,而不是拍脑袋填个整数。这也是云监控能帮上忙的地方——把 CVM 的 CPU、内存、磁盘 IO 指标接上告警,容器把资源吃满之前你就能收到信号。
容器日志膨胀:json-file 限制与轮转
这个坑几乎每个用 Docker 的人都踩过:某天发现系统盘满了,df -h 一查,/var/lib/docker/containers 下面某个容器的日志文件几十个 G。原因是 Docker 默认的 json-file 日志驱动不限制大小,应用往 stdout 打多少,它就存多少,日积月累把盘吃光。
解决办法是给日志驱动配上大小和份数限制。在 daemon.json 里设默认的 log-opts,限定单个日志文件大小和保留文件数,超过就轮转覆盖。也可以在单个容器上单独配。设完之后老容器的行为不会自动改,需要重建容器才生效,这个细节要注意。
更进一步的做法是把日志直接送到统一的日志服务,而不是留在本地磁盘。腾讯云日志服务 CLS 可以采集容器日志,配合采集配置和检索,能解决多机、多容器场景下"日志散落各处、出问题找不到"的盲区。本地日志的定位是应急排查,长期留存和检索应该交给集中式日志系统。 另外,容器日志写多了也意味着磁盘 IO 压力大,用高性能的云硬盘 CBS 或者把日志目录单独挂盘,能减少对业务数据的干扰。
容器网络与安全组:端口到底谁在管
新手常在这件事上犯迷糊:容器里服务监听了端口,外面到底能不能访问?答案取决于两层。容器自己的网络(默认 bridge)里,端口要在 docker run -p 或 compose 的 ports 里做映射,宿主机才监听这个端口;而宿主机这个端口能不能被公网访问,还要过腾讯云安全组这一关。
所以排查"访问不通",顺序是:容器是否在跑、端口映射对不对、服务在容器内是否正确监听 0.0.0.0 而不是 127.0.0.1(只监听本地回环是常见错误)、宿主机防火墙、最后才是安全组。很多"容器部署完访问不了"的问题,根子在应用绑定了 127.0.0.1,容器外根本连不上。
安全策略上,我建议只把真正需要对外的那一个入口端口在安全组放行,内部服务之间的通信走 Docker 内部网络,不对公网暴露。 数据库容器尤其不要直接映射到公网端口,需要外部访问就通过跳板机或内网。轻量应用服务器的防火墙逻辑与 CVM 安全组类似,同样在实例外做过滤,配置时两层都要对照。
镜像瘦身与仓库:轻量的内存红线
镜像越大,拉取越慢、占用越大、攻击面也越广。瘦身的常规手段:用 alpine 或 slim 这类精简基础镜像;多阶段构建,把编译工具链留在构建阶段,最终镜像只留运行时;合并 RUN 层并及时清理缓存和临时文件;.dockerignore 排除不需要的目录,别把本地一堆无关文件打进构建上下文。一个几百 MB 的镜像压到几十 MB,部署速度和磁盘占用都会明显改善。
镜像存哪也是问题。生产上建议搭建或使用私有镜像仓库,把业务镜像集中管理,配合 tag 规范和清理策略,避免仓库无限膨胀。公开镜像仓库适合基础镜像,业务镜像还是自己管更稳。
最后是那条内存红线。轻量应用服务器 Linux 套餐内存通常不大,跑一个系统加一个数据库容器就可能吃紧;如果你在一个小内存实例上再叠加缓存、消息队列,OOM 是迟早的事。用轻量套餐跑容器,先算清应用、数据库、系统各自的常驻内存之和,再决定盘上的基础镜像能不能省、该不该拆机或者换成内存更大的 CVM。 我见过在同一台小规格实例上塞四五个容器的客户,最后改成两台分工,稳定性立刻不一样。
下面这张表是容器部署里最常见的几个坑和对应做法。
常见坑 典型现象 根本原因 规避做法
数据写在容器层 重启或重建后数据丢失 可写层随容器生命周期消失 数据卷或绑定挂载持久化
未限制资源 整机卡死触发 OOM 容器可吃满宿主机资源 设置 memory 与 cpus 限制
日志不限制大小 系统盘被日志撑满 json-file 默认无上限 配置 log-opts 大小与轮转
应用只监听回环 容器外访问不通 服务绑定 127.0.0.1 监听 0.0.0.0 并核对映射
数据库映射公网 数据库被扫被入侵 端口直接暴露公网 走内网或跳板机访问
镜像过于臃肿 拉取慢 占用大 单阶段构建未清理 多阶段构建与精简基础镜像
轻量塞太多容器 频繁 OOM 重启 内存超出套餐上限 核算内存或拆分到更大实例
FAQ
Q:腾讯云服务器上 Docker 拉镜像很慢怎么办?
A:配置镜像加速器,在 daemon.json 里写 registry-mirrors 后重启 Docker。加速源会变化,使用前确认当年可用的地址,别照抄过期博客。
Q:为什么容器重启后我的数据不见了?
A:数据写在容器可写层里了,容器一删层就消失。数据库、上传文件、证书这类都要挂数据卷或绑定挂载到宿主机,才能跟着容器生命周期之外存续。
Q:一个容器把服务器搞卡死了是怎么回事?
A:多半是没做资源限制,容器内存膨胀触发内核 OOM Killer,拖着整机一起遭殃。给容器设 memory 与 cpus 上限,并把 CVM 指标接入云监控告警。
Q:容器端口映射了,安全组也放行了,还是访问不了?
A:先看应用是不是只监听了 127.0.0.1,改成监听 0.0.0.0;再依次核对容器状态、端口映射、宿主机防火墙,最后才看安全组,按这个顺序查最快。
Q:轻量应用服务器适合跑几个容器?
A:取决于套餐内存。系统、应用、数据库的常驻内存加起来别顶到上限,小内存套餐通常一两个核心服务就到头了,再往上加就该考虑换成内存更大的 CVM。
结语
给一条可执行的落地顺序:先把 /etc/docker/daemon.json 配好镜像加速和日志大小限制,再在 compose.yaml 里把每个服务的数据卷、restart 策略、资源限制一次性写全,用代码仓库管起来;上线后用 docker stats 看几眼真实的内存和 CPU 占用,据此把限制调准,并把 CVM 的指标接进云监控。容器跑起来不难,难的是让它长期稳定,而稳定的关键通常就藏