Appearance
工程实践与常见问题
这篇笔记聚焦 Docker 在真实项目里最常见的工程问题。
很多人第一次接触 Docker,会停留在:
- 会拉镜像
- 会启动容器
- 会写最简单的 Dockerfile
但项目里真正拉开差距的,通常不是“能不能跑起来”,而是:
- 镜像是否可维护
- 配置如何管理
- 日志怎么处理
- 容器异常后怎么排查
- 哪些东西该放进镜像,哪些不该放
1. 项目里为什么要关心镜像大小
镜像过大,带来的问题通常不只是“看起来不优雅”。
它会直接影响:
- 构建耗时
- 推送耗时
- 拉取耗时
- 存储成本
- 安全面
所以工程里常见的优化方向包括:
- 选更小的基础镜像
- 使用多阶段构建
- 避免把无关文件打进镜像
- 清理构建过程中的临时产物
2. .dockerignore 是什么,为什么很重要
.dockerignore 可以理解成 告诉 Docker 在构建镜像时,哪些文件不要带进构建上下文。
它解决的是:
- 无关文件进入镜像构建过程
- 构建上下文过大
- 本地缓存和敏感文件被意外打包
例如常见会忽略:
text
node_modules
dist
.git
.env
logs这里要特别注意:
.env 这类文件如果被直接打进镜像,后续镜像一旦被推送或共享,就可能造成敏感信息泄露。
3. 配置应该怎么注入
项目里很容易犯的错误是:把所有环境配置都直接写死在镜像里。
这会让镜像和环境强耦合。
更常见的工程思路是:
- 镜像尽量保持通用
- 环境差异通过环境变量或挂载配置注入
- 不同环境尽量复用同一份镜像
这里的 环境变量注入 可以理解成 容器启动时,由外部传入运行参数,而不是把这些参数提前写死在镜像中。
4. 日志为什么通常建议输出到标准输出
很多容器化应用会强调:应用日志优先输出到 stdout 和 stderr。
这是因为容器环境里更常见的思路是:
- 应用负责输出日志
- 容器平台负责采集日志
- 日志系统再统一存储、检索和分析
如果应用在容器里自己写本地文件日志,就会马上遇到:
- 日志文件位置不好统一管理
- 容器销毁后日志难保留
- 多容器环境下日志采集复杂
5. 为什么有些文件不应该放进镜像
以下内容通常不应该轻易打进镜像:
- 本地开发缓存
- 调试用日志
- 私钥和证书原件
.env敏感配置- 不必要的源码和历史产物
这不仅会让镜像变大,还可能带来安全问题。
6. 容器异常了,最常见的排查思路是什么
可以优先按这个顺序看:
- 容器是否启动成功
- 主进程是否退出
- 日志里有没有报错
- 端口映射是否正确
- 环境变量是否注入成功
- 外部依赖是否可连通
- 挂载目录权限是否正常
这里的 主进程 可以理解成 容器启动后最核心、最前台的那个进程。
Docker 容器的生命周期,通常就是跟着这个主进程走的。
如果主进程退出,容器往往也会结束。
7. 为什么“容器秒退”是高频问题
因为很多初学者会误以为:容器只要启动过一次,就应该一直在后台存在。
其实不对。
容器是否持续运行,取决于它的主进程是否仍在前台运行。
如果你启动的只是一个很快执行完的命令,容器就会立刻退出。
8. Docker Compose 在这里扮演什么角色
Docker Compose 可以理解成 用一份声明式配置,同时定义和启动多个相关容器。
它适合:
- 本地开发环境
- 多服务联调
- 应用、数据库、缓存一起拉起
它解决的是 多个容器之间如何一起启动、共享网络、共享卷和注入配置。
9. 一个典型的 Compose 示例
yaml
services:
app:
build: .
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: dev
depends_on:
- redis
redis:
image: redis:7
ports:
- "6379:6379"这份配置表达的是:
- 启动一个应用服务
- 启动一个 Redis 服务
- 应用依赖 Redis
- 通过声明式方式把本地联调环境一起描述出来
10. 项目里最常见的几类误区
10.1 误区一:镜像里写死所有环境配置
这样会让镜像难以复用,也会让环境切换变得笨重。
10.2 误区二:只要容器能跑起来,就算容器化完成
真正完整的容器化还要关注:
- 构建效率
- 配置管理
- 日志治理
- 数据持久化
- 安全边界
10.3 误区三:把 Docker 当成 Kubernetes 的替代品
两者不是同一个层次的问题。
Docker 更偏单机容器运行和镜像交付,Kubernetes 更偏集群编排和容器调度治理。
11. 一句话总结
Docker 的工程实践,真正要解决的不是“把程序塞进容器里”,而是:
如何把镜像构建、配置注入、日志输出、问题排查和多容器协作都变成一套可维护、可交付、可演进的工程流程。