Docker 最方便的地方,是把一组运行依赖写进一个可以搬动的格式。它不是把应用变成“自动部署”,也不是把服务器问题全部藏起来。镜像、容器、数据卷和网络各自负责什么,先分清楚以后,容器化才不会变成一层新的迷雾。
镜像是只读的构建结果,容器是它在某个时刻的运行实例。把数据写在容器可写层里,容器一删就没有了;数据库、上传文件和生成的索引应该放进卷或外部存储,并写清备份和恢复方式。docker compose down 能停掉服务,不等于数据已经安全。
Dockerfile 的每一层都会影响缓存和最终大小。依赖安装、源码复制和构建产物应该按变化频率排列,多阶段构建可以把编译工具留在构建阶段。镜像小一点不是唯一目标,构建是否可重复、基础镜像是否有安全更新同样重要。
Compose 适合描述一组相关服务的本地或单机运行方式:应用、数据库、缓存、反向代理。环境变量、端口和卷写在文件里以后,新电脑能更快开始,但生产环境仍然要审视默认密码、公开端口、日志和升级策略。复制一个 compose.yml 到服务器并不会自动产生可靠的运维。
容器网络也需要解释。服务名在 Compose 网络内可解析,浏览器却不能直接访问数据库容器;暴露端口是把主机端口映射出去,不等于服务之间都应该公开。把内部网络和外部入口分开,可以少掉很多误配置。
更新时最好使用不可变标签或明确的版本,而不是永远拉 latest。新容器启动以后先做健康检查,再切流量;迁移脚本要考虑重复执行和回滚。容器的“启动成功”只证明进程起来了,不证明业务能读写数据。
我喜欢 Docker,是因为它迫使依赖、端口和数据被写出来。写出来以后,才有机会比较、测试和回滚。部署从来不是一个按钮,它是一组可以被解释的边界。
镜像安全也值得单独检查:基础镜像是否仍在维护,运行进程是否需要 root,构建上下文有没有把本地凭据带进去。容器化让这些检查更容易自动化,但不会替我们决定风险是否可以接受。
容器化还要和发布流程接上。镜像标签、迁移脚本、健康检查和回滚版本应该能互相对应;新容器虽然启动了,仍要确认它能读写正确的数据,旧版本也要能在需要时重新运行。
我会把本地 Compose 与生产配置的差异列出来:端口、持久化目录、密钥来源、日志和备份各自在哪里。知道哪些部分只是开发便利,才能避免把一份本地文件直接当成生产运维方案。