Docker 部署入门
1. 一句话简介
Docker 是一个开源的容器化平台,将应用连同其运行时环境、依赖、配置一起打包进一个可移植的镜像(image),并通过容器(container)隔离运行,核心价值是解决「在我机器上能运行,换台机器就不行」的环境一致性问题。本模块演示了将 Spring Boot 应用容器化的完整流程:编写 Dockerfile(FROM openjdk:8-jdk-alpine 为基础镜像,ADD 将可执行 jar 复制为 app.jar,ENTRYPOINT ["java","-jar","/app.jar"] 设置启动命令),再用 docker build 手工或 dockerfile-maven-plugin(Spotify 1.4.9)在 mvn package 时自动构建镜像,最终通过 docker run -d -p 9090:8080 将宿主机 9090 端口映射到容器内 8080 端口,访问 http://localhost:9090/demo 即可获得 Hello,From Docker!。容器只需约 119MB 体积即可一键启动 Spring Boot 服务,无需在目标机上预装 JDK 和 Maven。
2. 什么时候使用
- ✅ 需要环境一致、消除「能跑不能跑」问题:本地开发、测试、生产使用同一个镜像,天然规避了 JDK 版本、系统库、中间件配置差异,本模块只用一条
docker run即可在任意装有 Docker 的主机上启动原本依赖 JDK 1.8 的服务。 - ✅ 应用需要快速、可重复地部署与扩展:容器秒级启动、按相同镜像复制出多副本,适合水平扩容、灰度发布、滚动更新等场景,比重新部署物理机或虚拟机快得多。
- ✅ 多服务依赖复杂,需一键编排启动:当 Spring Boot 服务依赖 MySQL、Redis、RabbitMQ 等外部组件时,可用 Docker 将每个依赖也容器化,配合 Docker Compose/Kubernetes 一键拉起整套环境。
- ✅ 希望实现 CI/CD 自动化镜像构建:本模块通过
dockerfile-maven-plugin将docker build绑定到mvn package,构建产物直接成为带版本标签(demo-docker:1.0.0-SNAPSHOT)的镜像,便于接入 Jenkins 等流水线。 - ✅ 追求镜像体积小、资源占用低:选用
openjdk:8-jdk-alpine轻量基础镜像(约 103MB),比完整 JDK 镜像(488MB)大幅缩减,适合资源受限的云主机或边缘节点。 - ❌ 单机简单应用、无扩展需求:只有一个实例、无多部门协作部署时,直接
java -jar运行即可,引入容器反而增加了 Docker 安装、镜像构建、端口映射的额外心智与运维负担。 - ❌ 涉及有状态数据且未善用卷机制:容器默认是无状态的,容器删除后数据即丢失。若应用依赖本地状态(如本地存储文件、临时日志落盘),需显式用
VOLUME/挂载卷持久化,否则不可用于生产。本模块虽声明VOLUME /tmp优化 Tomcat 临时文件,但真正的业务数据仍需挂载宿主机磁盘或外部存储。 - ❌ 安全合规要求严格的场景:容器与宿主机共享内核,隔离性弱于虚拟机,对内核级隔离、严格强隔离有硬性要求时需谨慎评估。
- ❌ 团队无容器/K8s 运维经验的初期:容器化不止是写个 Dockerfile,还涉及镜像仓库、编排、网络、存储、监控等一系列配套,基础设施团队能力不足时强行容器化反而拖慢交付。
3. 常见业务场景
微服务化部署的单个服务容器:每个 Spring Boot 服务打成一个镜像、运行一个容器,本模块演示了最小的容器化闭环——内置 Tomcat 监听 8080、Dockerfile EXPOSE 8080 声明端口、docker run -p 完成对外映射。将几十个类似服务各自容器化后,即可构成可独立发布、独立扩容的微服务体系。
测试/演示环境的快速搭建:对需要临时验证或给协作方演示的环境,用镜像一键克隆出完全相同且随时可销毁的服务,用完即 docker rm,无需污染开发机。本模块的 REST 接口 GET /demo 正是用来确认容器部署是否成功的探针。
CI/CD 流水线中的镜像制品化:利用 dockerfile-maven-plugin 在 mvn package 阶段自动 docker build,每次代码提交即产出带版本标签的镜像,直接推送到私有镜像仓库,部署环节拉取指定 tag 即可。镜像版本(${project.version})与代码版本天然对应,本模块的 tag 配置即体现了这一实践。
前后端一体交付:把前端构建产物、配置文件与后端 jar 一并打进同一镜像,实现「一个镜像包含完整可运行应用」,交付物从源码+部署手册简化为单个镜像,极大降低交付沟通成本。
演练容器编排与弹性伸缩:在单容器跑通(本模块级)后,用 Docker Compose 定义多服务,或用 Kubernetes 对同一镜像横向扩缩副本、实现故障自愈,是云原生改造的起点。
4. 同类技术对比
| 维度 | Docker | JVM 直跑(java -jar) | 虚拟机(VM) | Kubernetes |
|---|---|---|---|---|
| 打包尺度 | 应用+运行环境一起打包为镜像 | 仅打包应用 jar | 整机系统盘打包 | 镜像之上再做编排调度 |
| 启动速度 | 秒级 | 最快,毫秒级 | 分钟级 | 秒级(依赖镜像) |
| 环境一致性 | 高,同一镜像处处一致 | 依赖目标机预装 JDK 等环境 | 高 | 高 |
| 隔离性 | 进程级隔离,共享宿主机内核 | 无隔离 | 内核级强隔离 | 同 Docker,加网络隔离 |
| 资源占用 | 低,仅几百 MB~数百 MB 镜像 | 最低 | 高,整机 OS+内存 | 每业务一个 Pod 若干容器 |
| 多实例/调度 | 需手动或靠编排 | 需自行管理进程与端口 | 需自行管理 | 原生支持自动扩缩、调度、自愈 |
| 学习与运维成本 | 中,需懂 Dockerfile 与命令 | 最低,一条命令 | 高,维护整机系统 | 很高,需掌握整套生态 |
| 适用规模 | 单体到中型多服务 | 单机/小型应用 | 需强隔离的旧系统迁移 | 大规模微服务、K8s 原生环境 |
选型建议:追求最低复杂度、无多实例与跨环境交付需求时,直接 java -jar 最省事;一旦出现「多环境不一致、要快速交付、要水平扩容」,就应引入 Docker——它是现代后端从单体走向微服务、从手工部署走向云原生的事实标准。若安全合规要求内核级强隔离(如多租户敏感业务),才退而选择虚拟机;而上了多个容器的规模之后,再用 Kubernetes 做镜像的编排、动态扩缩容、滚动发布与故障自愈,二者是互补而非替代关系。整体路径建议是:单体 jar → 单容器 Docker → Compose 编排多服务 → Kubernetes 大规模平台化。