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 当成上线方案,短期能跑,但很快会遇到:怎么扩缩容?配置怎么热更新?日志怎么集中收集?健康检查挂了谁来拉起?