Docker Engine GitHub 71.5K Star,Docker Compose GitHub 37.3K Star——这是容器化生态的基石。Docker 解决”应用怎么跑”,Compose 解决”多个应用怎么一起跑”。两者配合,一条命令就能启动包含 Web 服务器、数据库、缓存的完整应用栈。
Docker 官网:docker.com · Engine 仓库:github.com/moby/moby · Compose 仓库:github.com/docker/compose · 文档:docs.docker.com
先搞清楚概念
什么是容器
容器是一个隔离的运行环境,里面只有你的应用和它的依赖——没有操作系统内核,没有多余的系统服务。它共享宿主机的内核,但文件系统、网络、进程都是隔离的。
| 维度 | 虚拟机 | 容器 |
|---|---|---|
| 隔离级别 | 硬件级(完整 OS) | 进程级(共享内核) |
| 启动速度 | 分钟级 | 秒级 |
| 磁盘占用 | GB 级 | MB 级 |
| 性能损耗 | 有虚拟化开销 | 接近原生 |
| 适用场景 | 强隔离需求 | 微服务、CI/CD、开发环境 |
容器不是轻量级虚拟机——它不模拟硬件,不运行完整操作系统。容器就是一个被隔离的进程,跑在宿主机内核上,但看起来像独占了一台机器。
什么是镜像
镜像是容器的只读模板。你把应用代码、运行环境、依赖库全部打包成一个镜像,然后在任何机器上用这个镜像启动容器——环境一致性问题就此解决。
Docker 做了什么
Docker 做了三件事:
- 构建镜像:用 Dockerfile 定义如何打包应用
- 分发镜像:通过 Docker Hub 等镜像仓库共享镜像
- 运行容器:从镜像启动隔离的运行环境
Docker Compose 做了什么
Docker 管单个容器,Compose 管多个容器。一个典型 Web 应用需要 Nginx + Node.js + MySQL + Redis 四个服务,用 Docker 你得手动启动四个容器、配网络、挂载卷。用 Compose,写一个 YAML 文件,一条命令全部启动。
安装
Docker Engine(Linux 服务器)
支持 Ubuntu、Debian、CentOS、RHEL、Fedora 等主流发行版。
Ubuntu/Debian 一键安装:
# 官方安装脚本(最简单)
curl -fsSL https://get.docker.com | sudo sh
# 将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
newgrp docker
CentOS/RHEL:
# 同样使用官方脚本
curl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable --now docker
安装完成后验证:
docker --version # Docker version 29.x.x
docker compose version # Docker Compose version v5.x.x
docker run hello-world # 测试运行
Docker Compose v2 已内置在 Docker Engine 中,作为 CLI 插件运行,使用
docker compose(无横线)。旧版独立docker-compose(Python 版)已停止维护。
Docker Desktop(Mac / Windows / Linux 桌面)
Docker Desktop 是 Docker 的桌面版,包含 Docker Engine + Compose + Kubernetes + GUI 管理界面。
| 平台 | 安装方式 |
|---|---|
| macOS | docker.com/products/docker-desktop 下载 DMG |
| Windows | 同上,下载安装包(需 WSL2) |
| Linux | 同上,下载 DEB/RPM 包 |
| 版本 | 价格 | 说明 |
|---|---|---|
| Personal | 免费 | 个人、小企业(<250 员工 且 收入 <$1000 万) |
| Pro | $5/月/人 | 个人开发者高级功能 |
| Team | $9/月/人 | 团队协作 |
| Business | $24/月/人 | 企业级安全和管理 |
大企业(>250 员工或年收入 >$1000 万)使用 Docker Desktop 需要付费订阅。Docker Engine 本身是开源的(Apache-2.0),不受此限制。
核心概念
Dockerfile:定义镜像
Dockerfile 是构建镜像的”配方”,从基础镜像开始,一层一层叠加:
# 基础镜像
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 复制依赖文件并安装
COPY package*.json ./
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
| 指令 | 作用 |
|---|---|
| FROM | 基础镜像 |
| WORKDIR | 容器内工作目录 |
| COPY | 复制文件到容器 |
| RUN | 构建时执行命令 |
| ENV | 设置环境变量 |
| EXPOSE | 声明端口(文档作用) |
| CMD | 容器启动命令 |
| ENTRYPOINT | 容器入口点 |
构建镜像:
docker build -t myapp:v1 .
镜像管理
docker images # 查看本地镜像
docker pull nginx:latest # 拉取镜像
docker push myrepo/myapp:v1 # 推送镜像
docker rmi myapp:v1 # 删除镜像
容器生命周期
docker run -d -p 3000:3000 --name myapp myapp:v1 # 创建并启动
docker ps # 查看运行中容器
docker stop myapp # 停止
docker start myapp # 启动
docker restart myapp # 重启
docker rm myapp # 删除
docker logs myapp # 查看日志
docker exec -it myapp sh # 进入容器
| 参数 | 作用 |
|---|---|
| -d | 后台运行 |
| -p 3000:3000 | 端口映射(宿主:容器) |
| —name myapp | 容器命名 |
| -v /host:/container | 挂载卷 |
| -e KEY=VALUE | 环境变量 |
| —restart unless-stopped | 自动重启策略 |
数据持久化
容器删除后数据就没了。持久化数据用 Volume 或 Bind Mount:
| 方式 | 命令 | 特点 |
|---|---|---|
| Volume | -v mydata:/var/lib/mysql | Docker 管理,推荐 |
| Bind Mount | -v /home/data:/var/lib/mysql | 绑定宿主目录 |
| tmpfs | --tmpfs /tmp | 内存存储,容器停止即消失 |
网络
docker network create mynet # 创建网络
docker run -d --network mynet --name app ... # 容器加入网络
同一网络内的容器可以用容器名互相访问——不需要知道对方的 IP。
Docker Compose 详解
compose.yaml 结构
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
- db
- redis
volumes:
- .:/app
restart: unless-stopped
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
db_data:
| 字段 | 作用 |
|---|---|
| services | 定义各个服务(容器) |
| build | 从 Dockerfile 构建 |
| image | 直接使用镜像 |
| ports | 端口映射 |
| environment | 环境变量 |
| depends_on | 启动依赖顺序 |
| volumes | 数据卷挂载 |
| restart | 重启策略 |
| networks | 网络配置 |
Compose 常用命令
docker compose up -d # 启动所有服务(后台)
docker compose down # 停止并删除所有容器
docker compose ps # 查看服务状态
docker compose logs -f web # 跟踪 web 服务日志
docker compose exec db bash # 进入 db 容器
docker compose build # 重新构建镜像
docker compose pull # 拉取最新镜像
docker compose restart web # 重启单个服务
docker compose up -d --build # 重新构建并启动
实战:完整 Web 应用
一个 Node.js + MySQL + Redis + Nginx 的完整项目结构:
project/
├── compose.yaml
├── web/
│ ├── Dockerfile
│ ├── package.json
│ └── server.js
└── nginx/
└── default.conf
compose.yaml:
services:
web:
build: ./web
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- web
restart: unless-stopped
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
db_data:
redis_data:
启动:
docker compose up -d
一条命令,四个服务全部启动,网络自动配置,依赖自动管理。
Compose Watch(开发热重载)
Compose v2.22+ 支持文件监听自动同步:
services:
web:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: ./package.json
docker compose watch # 启动监听模式
修改本地代码自动同步到容器,改 package.json 自动重新构建——不需要手动重启。
Docker vs Podman vs Nix
| 维度 | Docker | Podman | Nix |
|---|---|---|---|
| Star | 71.5K | 26K+ | 18K+ |
| 架构 | 客户端-服务端(daemon) | 无 daemon | 声明式包管理 |
| Root 权限 | 默认需要 | 不需要(rootless) | 不需要 |
| Compose | 原生支持 | 兼容(podman-compose) | 无 |
| 镜像兼容 | Docker Hub | Docker Hub | Nix Store |
| 生态 | 最成熟 | Red Hat 推动 | Nix 社区 |
| 学习曲线 | 低 | 低(Docker 兼容) | 高 |
Podman 是 Docker 的主要替代品——无需 daemon、默认 rootless、命令行语法兼容 Docker。但对于大多数人和团队,Docker 的生态成熟度和文档覆盖面仍然是选择它的理由。
容器化最佳实践
| 实践 | 说明 |
|---|---|
| 使用多阶段构建 | 构建阶段用完整镜像,运行阶段用精简镜像,最终镜像体积小 10 倍 |
| 固定镜像版本 | node:20-alpine 而不是 node:latest,避免不可控变更 |
| 使用 .dockerignore | 排除 node_modules、.git 等,加速构建 |
| 一个容器一个进程 | 不要在一个容器里跑 Nginx + Node.js |
| 善用健康检查 | healthcheck 让 Docker 知道容器是否真的健康 |
| 不在镜像里存密钥 | 用环境变量或 Docker Secrets 传入 |
| 合理利用缓存 | Dockerfile 中把不常变的层(npm install)放前面 |
多阶段构建示例:
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 运行阶段(只有构建产物,没有源码和 devDependencies)
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]
常用镜像选择
| 用途 | 推荐镜像 | 大小 |
|---|---|---|
| Node.js | node:20-alpine | ~180 MB |
| Python | python:3.12-slim | ~150 MB |
| Go | golang:1.22-alpine | ~300 MB(构建用) |
| Nginx | nginx:alpine | ~40 MB |
| MySQL | mysql:8 | ~580 MB |
| PostgreSQL | postgres:16-alpine | ~230 MB |
| Redis | redis:7-alpine | ~40 MB |
| Alpine | alpine:3.19 | ~7 MB |
-alpine后缀表示基于 Alpine Linux 的精简版,体积远小于标准版。生产环境推荐优先选择 alpine 变体,除非有 glibc 兼容性问题。
写在最后
Docker 改变的不仅是部署方式——它改变了软件交付的整个链路。开发者用 Dockerfile 定义环境,用 Compose 编排服务,CI/CD 用镜像做交付件,运维用容器做编排。从”在我机器上能跑”到”在容器里能跑”,环境一致性问题被彻底解决。
Docker 解决的核心问题只有一个:环境一致性。从开发机到测试环境到生产服务器,同一个镜像跑出来的行为完全一致。Compose 在此基础上解决第二个问题:多服务编排。两者配合,才是容器化开发的完整答案。