Docker与Docker Compose核心区别解析
引言:容器化的普及与两款工具的定位
容器化已经成为交付与部署的默认选型:开发者希望在开发、测试、生产保持“环境一致”,运维希望快速弹性扩缩容,业务希望缩短交付周期。Docker 提供了打包、分发、运行单个容器的基础能力,是现代容器生态的“底座”。在单服务变多服务后,手写多条 docker run 命令管理网络、依赖和环境变量会迅速失控,Docker Compose 便作为“基于 Docker 的多容器编排工具”进入视野,负责把一组服务声明式地组织在一起。
核心对比:定位、功能、场景一览
| 维度 | Docker | Docker Compose |
|---|---|---|
| 核心定位 | 单容器生命周期管理工具 | 多容器(多服务)编排工具 |
| 核心功能 | 构建镜像、运行/停止容器、管理网络/卷(命令级) | 声明式定义一组服务、网络、卷,统一启动/停止/扩缩容 |
| 操作对象 | 单个镜像/容器 | 成组的服务(每个服务对应一个或多个容器) |
| 配置方式 | 命令行参数 + Dockerfile | docker-compose.yml 声明式配置 |
| 适用场景 | 单体或单服务部署、调试;验证镜像 | 本地/测试环境的多服务联调,CI 端快速拉起依赖(DB、MQ 等) |
| 依赖关系 | 直接调用 Docker Engine API | 依赖 Docker;Compose 自身不运行容器,只生成并下发 Docker 指令 |
通俗比喻:Docker 像一个“单兵作战的工人”,能独立完成容器的构建与运行;Docker Compose 像“工头”,根据一本“施工蓝图”(docker-compose.yml)指挥多名工人协同完成整体工程。
实战案例
案例1:用纯 Docker 命令部署一个 Spring Boot 应用
目标:构建镜像并运行单服务。
- 编写
Dockerfile(位于 Spring Boot 项目根目录)
# 选择合适的 JDK 运行时镜像
FROM eclipse-temurin:17-jre
WORKDIR /app
# 将编译好的 jar 拷贝进容器
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar
# 暴露应用端口(仅文档标注,实际发布依赖运行时映射)
EXPOSE 8080
# 入口命令
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
- 构建镜像
docker build -t demo-springboot:1.0.0 .
- 运行容器
# --name:容器名;-p:端口映射;-d:后台运行
docker run --name demo-app -p 8080:8080 -d demo-springboot:1.0.0
常见问题排查
- 端口映射错误:容器内端口与应用监听端口不一致,需校准
EXPOSE与-p映射,例如应用监听 8081,则docker run -p 8080:8081 ...。 - JDK 版本不符:镜像 JDK 版本需与编译目标一致(如项目使用 Java 17,基础镜像也应为 JRE 17)。
案例2:用 Docker Compose 部署 Spring Boot + MySQL
目标:一条命令拉起应用与数据库,并处理网络与依赖顺序。
- 编写
docker-compose.yml
version: "3.9"
services:
app:
image: demo-springboot:1.0.0 # 复用上一步构建的镜像
container_name: demo-app
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/demo?useSSL=false&serverTimezone=UTC
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=123456
depends_on:
- db # 声明启动顺序依赖
db:
image: mysql:8.0
container_name: demo-mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=demo
volumes:
- db-data:/var/lib/mysql # 数据持久化
ports:
- "3306:3306"
volumes:
db-data: # 定义持久化卷
- 启动与停止
# 启动
docker compose up -d
# 查看日志
docker compose logs -f app
# 停止并清理(保留卷)
docker compose down
- 关键点说明
- 网络自动创建:Compose 默认为项目创建专用网络,服务间可通过服务名互相访问(示例中
db即为 MySQL 主机名),无需手动docker network create。 - 启动顺序:
depends_on保证容器按序拉起,但不等待服务“就绪”。对数据库类服务,可在应用端配置重试或使用healthcheck。 - 配置集中:端口、环境变量、卷都在 YAML 中声明,避免多条命令重复输入。
常见问题排查
- 服务名写错:
SPRING_DATASOURCE_URL中的主机名应与 Compose 服务名一致(db),否则会出现连接失败。 - 端口冲突:宿主机端口已被占用时,调整
ports映射如"18080:8080"。 - MySQL 初始化失败:检查
MYSQL_ROOT_PASSWORD是否符合策略,或查看docker compose logs db获取详细错误。
纯 Docker 多服务痛点回顾
- 需手动创建网络并为每个
docker run指定--network,易漏配。 - 启动顺序与环境变量分散在多条命令中,维护成本高。
- 卷、端口、环境变量重复书写,团队协作易出错。
关键补充
- 依赖关系:Docker 是基础命令与守护进程,Compose 只是读取 YAML,组装并调用 Docker API;没有 Docker,Compose 无法运行。
- 生产选型与 K8s 简述:Compose 更适合本地开发、集成测试、小规模单机或小集群场景;生产级大规模集群通常选用 Kubernetes 等编排系统。Compose 不负责跨主机调度、自动扩缩容与服务发现,但能作为本地模拟环境的高效工具。
结尾总结:何时用哪一个?
- 仅单服务或临时验证:用 Docker,
docker build+docker run足够简单直接。 - 本地/测试多服务联调:用 Docker Compose,一份 YAML 管理网络、依赖、环境与卷,降低手工错误。
- 生产大规模编排:Docker Compose 可用于 PoC 或小规模部署;需要弹性调度、自动恢复、滚动升级时,应考虑 Kubernetes 等更完整的编排系统。
扩展思考
- Docker Compose 天然是单机编排,不支持跨主机调度与弹性扩缩容;随着服务数量和可靠性要求提升,建议逐步学习并迁移到 Kubernetes 或 Swarm 等集群编排方案。