Docker 和 Docker Compose 到底差在哪?一文讲清用法和配置
Docker 和 Docker 的区别|附配置文件
说明:很多人在搜索或写标题时,会把“Docker 和 Docker Compose 的区别”误写成“Docker 和 Docker 的区别”。从实际使用场景来看,开发者通常想了解的是 Docker 与 Docker Compose 的区别,以及它们各自应该如何配置和使用。本文将围绕这个方向展开,并附上常见配置文件示例。
一、什么是 Docker?
Docker 是一种容器化技术平台,它可以把应用程序及其运行环境打包成一个独立的容器,让应用可以在不同机器、不同系统环境中保持一致运行。
简单来说,Docker 解决的是这样一个问题:
“为什么我本地能跑,到了服务器就跑不起来?”
在传统部署方式中,一个应用可能依赖:
- 操作系统版本
- JDK / Node.js / Python / PHP 等运行环境
- 系统库文件
- 环境变量
- 配置文件
- 数据库连接
- 端口配置
如果开发环境和生产环境存在差异,就很容易出现各种兼容性问题。
Docker 的核心思想是:
把应用和运行环境一起打包,形成镜像,然后基于镜像启动容器。
二、Docker 的核心概念
在理解 Docker 和 Docker Compose 的区别之前,需要先掌握 Docker 中几个重要概念。
1. 镜像 Image
镜像可以理解为一个只读模板,里面包含应用程序、依赖环境、系统库、配置等内容。
例如:
nginx:latest
mysql:8.0
redis:7
node:20
openjdk:17
这些都是常见镜像。
你可以通过以下命令拉取镜像:
docker pull nginx:latest
查看本地镜像:
docker images
2. 容器 Container
容器是镜像运行起来之后的实例。
镜像类似“类”,容器类似“对象”。
例如基于 Nginx 镜像启动一个容器:
docker run -d \
--name my-nginx \
-p 8080:80 \
nginx:latest
含义如下:
| 参数 | 说明 |
|---|---|
-d |
后台运行 |
--name my-nginx |
指定容器名称 |
-p 8080:80 |
将宿主机 8080 端口映射到容器 80 端口 |
nginx:latest |
使用的镜像 |
启动后访问:
http://localhost:8080
就可以看到 Nginx 页面。
3. Dockerfile
Dockerfile 是用来构建 Docker 镜像的配置文件。
例如,一个 Node.js 项目的 Dockerfile 可以这样写:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
它的作用是:
- 使用
node:20-alpine作为基础镜像; - 设置工作目录为
/app; - 复制依赖文件;
- 安装依赖;
- 复制项目代码;
- 暴露 3000 端口;
- 启动应用。
构建镜像:
docker build -t my-node-app:1.0 .
运行容器:
docker run -d \
--name node-app \
-p 3000:3000 \
my-node-app:1.0
三、什么是 Docker Compose?
Docker Compose 是 Docker 官方提供的一个多容器编排工具。
如果说 Docker 更偏向于管理单个容器,那么 Docker Compose 更适合管理一组容器。
在实际项目中,一个完整系统通常不只有一个应用容器,例如:
- 后端服务
- 前端服务
- MySQL 数据库
- Redis 缓存
- Nginx 网关
- RabbitMQ 消息队列
- Elasticsearch 搜索服务
如果只使用 Docker 命令,每个服务都需要写一大串 docker run 命令:
docker run -d --name mysql ...
docker run -d --name redis ...
docker run -d --name backend ...
docker run -d --name nginx ...
当服务数量变多时,管理起来会非常麻烦。
Docker Compose 的作用就是:
用一个
docker-compose.yml文件描述多个容器,并通过一条命令统一启动、停止和管理。
四、Docker 和 Docker Compose 的区别
下面通过表格对比二者区别。
| 对比项 | Docker | Docker Compose |
|---|---|---|
| 定位 | 容器化平台 | 多容器编排工具 |
| 管理对象 | 镜像、容器、网络、卷等 | 多个服务组成的应用 |
| 常用文件 | Dockerfile | docker-compose.yml |
| 使用方式 | 命令行操作单个容器较多 | 配置文件统一管理多个容器 |
| 适用场景 | 构建镜像、运行单容器 | 本地开发、测试环境、中小型部署 |
| 启动命令 | docker run |
docker compose up |
| 配置复杂度 | 参数多时命令较长 | 配置集中,更易维护 |
| 是否替代关系 | 不是 | 基于 Docker 工作 |
需要注意:
Docker Compose 并不是 Docker 的替代品,而是 Docker 的补充工具。
Docker Compose 底层仍然依赖 Docker。
没有 Docker,Docker Compose 无法单独运行。
五、一个简单例子:只使用 Docker 启动 MySQL
假设我们要启动一个 MySQL 8.0 容器,如果使用 Docker 命令,可以这样写:
docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=test_db \
-v mysql_data:/var/lib/mysql \
mysql:8.0
这个命令包含了:
- 容器名称
- 端口映射
- 环境变量
- 数据卷挂载
- 镜像版本
虽然这个例子还不算复杂,但如果参数继续增加,命令会越来越长,可读性和维护性都会下降。
六、使用 Docker Compose 启动 MySQL
如果使用 Docker Compose,可以创建一个 docker-compose.yml 文件:
services:
mysql:
image: mysql:8.0
container_name: mysql8
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: test_db
TZ: Asia/Shanghai
volumes:
- mysql_data:/var/lib/mysql
command:
--default-authentication-plugin=mysql_native_password
volumes:
mysql_data:
然后执行:
docker compose up -d
停止服务:
docker compose down
查看日志:
docker compose logs -f mysql
相比一长串命令,Compose 配置文件更清晰,也更适合团队协作和版本管理。
七、完整项目示例:后端 + MySQL + Redis
下面给出一个更接近实际项目的配置示例。
项目结构如下:
demo-project
├── backend
│ ├── Dockerfile
│ ├── package.json
│ └── src
│ └── index.js
├── docker-compose.yml
└── .env
八、后端服务 Dockerfile 配置
假设后端是一个 Node.js 服务,可以在 backend/Dockerfile 中写入:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --registry=https://registry.npmmirror.com
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
这个 Dockerfile 用于构建后端镜像。
如果你的后端是 Java Spring Boot,也可以使用类似配置:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
如果是 Go 项目,也可以采用多阶段构建:
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o server main.go
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]
不同语言的 Dockerfile 写法不完全相同,但核心思路一致:
- 选择基础镜像;
- 设置工作目录;
- 复制代码和依赖文件;
- 安装依赖或编译项目;
- 暴露端口;
- 设置启动命令。
九、docker-compose.yml 配置文件
下面是一个后端服务、MySQL、Redis 同时启动的配置:
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: demo-backend
restart: always
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: mysql
DB_PORT: 3306
DB_NAME: demo_db
DB_USER: root
DB_PASSWORD: 123456
REDIS_HOST: redis
REDIS_PORT: 6379
TZ: Asia/Shanghai
depends_on:
- mysql
- redis
networks:
- demo-net
mysql:
image: mysql:8.0
container_name: demo-mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: demo_db
TZ: Asia/Shanghai
volumes:
- mysql_data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
- ./mysql/init:/docker-entrypoint-initdb.d
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
networks:
- demo-net
redis:
image: redis:7-alpine
container_name: demo-redis
restart: always
ports:
- "6379:6379"
command:
redis-server --requirepass 123456 --appendonly yes
volumes:
- redis_data:/data
networks:
- demo-net
volumes:
mysql_data:
redis_data:
networks:
demo-net:
driver: bridge
这个配置文件中定义了三个服务:
backend:后端应用;mysql:数据库;redis:缓存服务。
其中,backend 服务通过 DB_HOST: mysql 连接数据库,通过 REDIS_HOST: redis 连接 Redis。
这是 Docker Compose 中非常重要的特性:
同一个 Compose 网络中的服务,可以通过服务名互相访问。
也就是说,后端应用不需要写 MySQL 容器的 IP 地址,只需要写服务名 mysql。
十、使用 .env 管理环境变量
在实际项目中,不建议把密码、端口等配置全部硬编码在 docker-compose.yml 中。
可以使用 .env 文件统一管理。
.env 示例:
APP_PORT=3000
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=demo_db
MYSQL_PORT=3306
REDIS_PASSWORD=123456
REDIS_PORT=6379
TZ=Asia/Shanghai
然后改造 docker-compose.yml:
services:
backend:
build:
context: ./backend
container_name: demo-backend
restart: always
ports:
- "${APP_PORT}:3000"
environment:
NODE_ENV: production
DB_HOST: mysql
DB_PORT: 3306
DB_NAME: ${MYSQL_DATABASE}
DB_USER: root
DB_PASSWORD: ${MYSQL_ROOT_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD}
TZ: ${TZ}
depends_on:
- mysql
- redis
networks:
- demo-net
mysql:
image: mysql:8.0
container_name: demo-mysql
restart: always
ports:
- "${MYSQL_PORT}:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
TZ: ${TZ}
volumes:
- mysql_data:/var/lib/mysql
networks:
- demo-net
redis:
image: redis:7-alpine
container_name: demo-redis
restart: always
ports:
- "${REDIS_PORT}:6379"
command:
redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- redis_data:/data
networks:
- demo-net
volumes:
mysql_data:
redis_data:
networks:
demo-net:
driver: bridge
这样做的好处是:
- 配置更加清晰;
- 不同环境可以使用不同
.env文件; - 敏感信息更容易统一管理;
- Compose 文件更通用。
需要注意的是,如果项目上传到 Git 仓库,建议不要直接提交真实的 .env 文件,而是提交 .env.example。
例如:
APP_PORT=3000
MYSQL_ROOT_PASSWORD=your_password
MYSQL_DATABASE=your_database
MYSQL_PORT=3306
REDIS_PASSWORD=your_redis_password
REDIS_PORT=6379
TZ=Asia/Shanghai
十一、Docker Compose 常用命令
1. 启动服务
docker compose up -d
-d 表示后台运行。
2. 停止并删除容器
docker compose down
如果想同时删除数据卷:
docker compose down -v
注意:
-v 会删除数据卷,数据库数据可能会丢失,生产环境慎用。
3. 查看服务状态
docker compose ps
4. 查看日志
查看全部日志:
docker compose logs -f
查看某个服务日志:
docker compose logs -f backend
5. 重新构建镜像并启动
docker compose up -d --build
当后端代码或 Dockerfile 修改后,通常需要执行这个命令。
6. 进入容器
docker exec -it demo-backend sh
如果容器内是 Debian 或 Ubuntu 系统,也可以使用:
docker exec -it demo-backend bash
7. 删除未使用资源
docker system prune
如果要删除未使用镜像、容器、网络和构建缓存:
docker system prune -a
该命令也要谨慎使用,避免误删仍需要的镜像。
十二、什么时候用 Docker,什么时候用 Docker Compose?
适合直接使用 Docker 的场景
如果只是临时启动一个单独服务,例如:
- 启动一个 Nginx 测试页面;
- 启动一个 Redis 做临时测试;
- 构建某个应用镜像;
- 查看容器运行状态;
- 调试单个容器。
这时候直接使用 Docker 命令即可。
例如:
docker run -d --name redis-test -p 6379:6379 redis:7-alpine
这种方式简单直接。
适合使用 Docker Compose 的场景
如果你的项目包含多个服务,例如:
- Web 应用 + MySQL;
- 后端服务 + Redis;
- 前端 + 后端 + 数据库;
- 微服务项目;
- 本地开发环境;
- 测试环境部署。
这时更推荐使用 Docker Compose。
因为它可以把所有服务关系都写进一个配置文件中,方便启动、停止、迁移和维护。
十三、常见误区
误区一:Docker Compose 可以替代 Docker
不可以。
Docker Compose 是基于 Docker 的工具,它调用 Docker 引擎来创建和管理容器。
如果没有 Docker,Compose 不能独立完成容器运行。
误区二:Dockerfile 和 docker-compose.yml 是同一个东西
不是。
二者作用不同:
| 文件 | 作用 |
|---|---|
Dockerfile |
描述如何构建镜像 |
docker-compose.yml |
描述如何运行多个服务 |
Dockerfile 关注的是“镜像怎么做”。
docker-compose.yml 关注的是“容器怎么跑”。
误区三:有了 Compose 就不用写 Dockerfile
不一定。
如果你使用的是官方镜像,例如 MySQL、Redis、Nginx,可以不写 Dockerfile,直接在 Compose 中指定镜像。
但如果你要运行自己的业务代码,比如 Java、Node.js、Go、Python 项目,通常仍然需要 Dockerfile 来构建自定义镜像。
误区四:depends_on 能保证数据库完全启动成功
depends_on 只能保证容器启动顺序,不能保证服务已经完全可用。
例如 MySQL 容器启动了,但数据库初始化还没完成,后端应用立即连接可能会失败。
更稳妥的做法是:
- 应用自身增加重试机制;
- 使用健康检查
healthcheck; - 在启动脚本中等待服务可用。
示例:
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: demo_db
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p123456"]
interval: 10s
timeout: 5s
retries: 5
十四、生产环境使用建议
Docker Compose 可以用于中小型项目部署,但在生产环境中需要注意以下几点:
-
不要使用弱密码
示例中的123456仅用于演示,生产环境必须使用高强度密码。 -
不要随意暴露数据库端口
如果后端和数据库都在同一 Docker 网络中,MySQL 不一定需要映射到宿主机端口。 -
做好数据卷备份
MySQL、Redis 等有状态服务需要定期备份数据。 -
固定镜像版本
不建议生产环境使用latest,最好指定明确版本,例如mysql:8.0.36。 -
配置日志策略
避免容器日志无限增长,占满磁盘。
示例:
logging:
driver: json-file
options:
max-size: "100m"
max-file: "3"
- 区分开发、测试、生产配置
可以使用多个 Compose 文件,例如:
docker-compose.yml
docker-compose.dev.yml
docker-compose.prod.yml
启动生产配置:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
十五、总结
如果用一句话总结 Docker 和 Docker Compose 的区别:
Docker 负责容器化,Docker Compose 负责把多个容器组织起来一起运行。
更具体地说:
- Docker 主要用于构建镜像、运行容器、管理镜像和容器资源;
- Dockerfile 用于描述镜像构建过程;
- Docker Compose 用于通过配置文件管理多个服务;
- docker-compose.yml 用于描述服务、网络、数据卷、环境变量和依赖关系。
在单容器场景下,直接使用 Docker 命令即可。
在多服务项目中,推荐使用 Docker Compose,因为它更清晰、更易维护,也更适合团队协作。
对于日常开发来说,最佳实践通常是:
- 使用 Dockerfile 构建业务服务镜像;
- 使用 docker-compose.yml 编排应用、数据库、缓存等服务;
- 使用
.env管理环境变量; - 使用数据卷持久化重要数据;
- 使用固定版本镜像保证环境稳定;
- 在生产环境中加强安全、备份和日志管理。
掌握 Docker 与 Docker Compose 的区别之后,就能更合理地设计项目部署方案,让开发、测试和上线流程更加统一、稳定和高效。