Docker是运行时容器引擎,核心价值在于让应用运行可重复、可验证、可移交、可回滚;关键实践包括分层构建优化缓存、CI中禁用端口映射、生产环境必须用编排工具、镜像需扫描漏洞并固定基础镜像标签。

Docker 是一个运行时容器引擎,不是虚拟机,也不是部署平台本身——它把应用和它的依赖(库、配置、环境变量、甚至内核模块兼容性要求)打包成一个可执行的、带版本的镜像,然后在宿主机上隔离运行这个镜像的实例(即容器)。
它在 DevOps 中真正起作用的地方,从来不是“让程序跑起来”,而是**让“跑起来”这件事变得可重复、可验证、可移交、可回滚**。下面说几个关键实操点。
为什么 Dockerfile 里不能写 RUN npm install 而要拆成 COPY package.json + RUN npm install
这是构建缓存失效最典型的坑。Docker 构建是分层的,每一行 RUN、COPY 都可能生成一层缓存。如果把 npm install 放在最后,只要源码任意一行变了,整个安装过程就得重来——CI 流水线动辄多花 3–5 分钟。
- 正确顺序:
COPY package.json .→RUN npm install→COPY . . - 这样改了 JS 文件不会触发重装依赖,只重建最上层;改了
package.json才重装 - 同理适用于
pip install -r requirements.txt、go mod download等场景
测试阶段用同一镜像,但别在 CI 里 docker run -p 8080:8080
很多团队在 Jenkins 或 GitLab CI 里直接 docker run 启服务再跑集成测试,结果发现端口冲突、容器没清理、日志捕获困难——这不是 Docker 的错,是误用了运行模型。
- CI 中应使用
docker run --rm -i启动,并确保测试套件能通过 HTTP/IPC 连上容器(比如用localhost:3000) - 禁止映射宿主机端口(
-p),因为并发任务会抢端口;改用--network host或容器内网通信(如curl http://app:8080/health) - 测试完必须加
--rm,否则失败任务残留容器,占资源还污染后续构建
生产环境里 docker run 只能当临时调试命令,上线必须用编排工具
有人把 docker run -d --restart=always 当成上线方案,短期能跑,但很快会遇到:怎么扩缩容?配置怎么热更新?日志怎么集中收集?健康检查挂了谁来拉起?
- 哪怕只有单节点,也该用
docker-compose.yml管理启动参数、网络、卷、健康检查 - 跨节点或需高可用,必须上
Kubernetes或至少Docker Swarm;否则运维成本指数级上升 - 特别注意:K8s 的
livenessProbe和readinessProbe必须基于容器内真实进程状态,不能只 ping 端口
镜像推送前不扫描,等于把漏洞打包发到生产
你本地 docker build 成功,不代表安全。基础镜像含已知 CVE、应用依赖带高危漏洞、甚至构建中间层残留了密钥——这些都不会报错,但会在生产环境爆发。
- CI 流水线中必须插入镜像扫描步骤,例如:
trivy image --severity CRITICAL myapp:latest - 拒绝使用
FROM ubuntu:latest或node:alpine这类无固定 tag 的镜像,它们每天都在变,破坏可重现性 - 推荐用 distroless 镜像(如
gcr.io/distroless/nodejs)减少攻击面,但要注意调试工具缺失带来的排障成本










