Docker 是开源的应用容器引擎,让开发者把应用及其所有依赖打包到一个标准化的"容器"中,这个容器可以在任何安装了 Docker 的环境中一致运行——从开发者的笔记本到测试服务器,再到生产环境的云主机。Docker 解决了"在我机器上能跑"的经典问题,是现代 DevOps 和云原生应用的基础。
一、Docker 解决了什么问题
1.1 部署环境不一致的噩梦
开发者机器:Node.js 18 + Ubuntu 22.04
测试服务器:Node.js 16 + CentOS 7
生产环境:Node.js 20 + Alpine Linux
结果:同样的代码,三个环境三种表现
Docker 的解法:把应用和它所需的一切(运行时、系统库、配置文件)打包成一个镜像,在任何支持 Docker 的地方运行完全一致的环境。
1.2 Docker 与虚拟机的区别
| 维度 | 虚拟机(VM) | Docker 容器 |
|---|---|---|
| 虚拟化层级 | 硬件级(Hypervisor) | 操作系统级(Kernel Namespaces/Cgroups) |
| Guest OS | 每个 VM 独立完整 OS | 共享宿主机内核 |
| 启动时间 | 分钟级 | 秒级 |
| 资源占用 | 数 GB / 每个 VM | MB 级 / 每个容器 |
| 性能损耗 | 10-20% | < 5% |
| 隔离性 | 强(硬件隔离) | 进程级(够用但弱于 VM) |
| 密度 | 一台物理机 10-100 个 VM | 一台物理机 1000+ 容器 |
核心认知:Docker 不是虚拟机,它是运行在宿主机操作系统上的隔离进程,利用 Linux Kernel 的 Namespaces(隔离)、Cgroups(资源限制)、UnionFS(分层文件系统)实现轻量级虚拟化。
二、核心概念
2.1 镜像(Image)
镜像是一个只读模板,包含运行应用所需的一切:代码、运行时、库、环境变量、配置文件。镜像由分层(Layer)结构组成:
镜像分层结构(从底到顶)
├── 基础镜像层:Alpine Linux(5MB)
├── 依赖层:安装 Node.js(50MB)
├── 应用依赖层:npm install(100MB)
└── 应用代码层:COPY . /app(10MB)
= 总镜像大小 ~165MB
分层的好处:多个镜像可以共享相同的底层。例如 10 个 Node.js 应用镜像都基于 node:18-alpine,基础层只在磁盘存一份。
2.2 容器(Container)
容器是镜像的运行实例。你可以把镜像理解为类(Class),容器理解为对象(Object):
# 从镜像运行一个容器
docker run -d -p 3000:3000 --name my-app my-image
# 查看运行中的容器
docker ps
# 停止容器
docker stop my-app
# 删除容器
docker rm my-app
容器的特性:
- 隔离性:每个容器有自己的文件系统、网络、进程空间
- 可写层:容器运行时对文件系统的修改写入一个可写层(Copy-on-Write)
- 临时性:容器删除后,可写层数据丢失(需要用 Volume 持久化)
2.3 Dockerfile
Dockerfile 是定义镜像构建步骤的文本文件:
# 使用官方 Node.js 轻量镜像作为基础
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 先复制依赖文件(利用缓存:只要 package.json 不变,npm install 层就不重建)
COPY package.json package-lock.json ./
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
2.4 仓库(Registry)
Docker Hub 是公共镜像仓库(类似 npm registry):
# 拉取官方镜像
docker pull node:20-alpine
# 推送自己的镜像到 Docker Hub
docker tag my-app username/my-app:v1.0
docker push username/my-app:v1.0
替代方案:自建 Registry、AWS ECR、阿里云容器镜像服务、GitHub Container Registry。
三、安装与第一个容器
3.1 安装 Docker
# macOS
brew install --cask docker
# Ubuntu
sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl start docker
# Windows
# 下载 Docker Desktop for Windows
# 验证安装
docker --version
# Docker version 27.0.0, build xxx
3.2 运行第一个容器
# 运行 Hello World
docker run hello-world
# 运行一个 Nginx 服务器
docker run -d -p 8080:80 --name my-nginx nginx
# -d: 后台运行
# -p 8080:80: 把容器的 80 端口映射到宿主机的 8080
# --name: 给容器命名
# 浏览器访问 http://localhost:8080
3.3 常用命令速查
# 镜像操作
docker images # 列出本地镜像
docker rmi image_id # 删除镜像
docker build -t my-app . # 构建镜像
docker pull nginx # 拉取镜像
docker push username/my-app # 推送镜像
# 容器操作
docker ps # 运行中的容器
docker ps -a # 所有容器(包括停止的)
docker start my-container # 启动容器
docker stop my-container # 停止容器
docker restart my-container # 重启
docker rm my-container # 删除容器
docker logs my-container # 查看日志
docker exec -it my-container sh # 进入容器内部
# 系统维护
docker system prune # 清理未使用的镜像/容器/网络/缓存
docker volume ls # 列出 Volume
docker network ls # 列出网络
四、Docker 工作流
1. 编写应用代码
↓
2. 编写 Dockerfile(定义镜像怎么构建)
↓
3. 构建镜像:docker build -t my-app .
↓
4. 本地测试运行:docker run -p 3000:3000 my-app
↓
5. 推送到 Registry:docker push my-app
↓
6. 在服务器上拉取运行:docker pull my-app && docker run my-app
五、数据持久化:Volume
容器是临时的,数据需要持久化存储:
# 创建 Named Volume
docker volume create my-data
# 运行容器时挂载 Volume
docker run -v my-data:/app/data my-app
# 或者挂载宿主机目录
docker run -v /host/path:/container/path my-app
# 查看 Volume
docker volume ls
docker volume inspect my-data
| 方式 | 适用场景 |
|---|---|
| Named Volume | 数据库数据、配置文件(Docker 管理) |
| Bind Mount | 开发时代码热重载(宿主机目录直接映射) |
| ** tmpfs Mount** | 敏感数据(不写入磁盘,只在内存) |
六、网络通信
Docker 默认创建三种网络:
| 网络类型 | 说明 |
|---|---|
| bridge | 默认,容器间通过内部 IP 通信 |
| host | 容器直接使用宿主机网络 |
| none | 无网络 |
# 查看容器 IP
docker inspect my-container | grep IPAddress
# 容器间通信(通过容器名,需要自定义网络)
docker network create my-network
docker run -d --name db --network my-network postgres
docker run -d --name api --network my-network my-api
# 在 api 容器内可以通过 http://db:5432 访问数据库
七、常见问题(FAQ)
Docker 和 Kubernetes 有什么关系?
Docker 是容器运行时( run containers),Kubernetes 是容器编排平台(orchestrate containers at scale)。简单类比:Docker 像单台车的引擎,K8s 像管理整个车队的调度系统。详见 Docker vs Kubernetes 对比与选型。
Docker 收费吗?
Docker Engine(核心运行时)完全免费开源。Docker Desktop 对个人和教育免费,企业使用需要 Docker Business 订阅。
容器数据会丢失吗?
容器停止/删除后,容器内的可写层数据会丢失。需要持久化的数据必须使用 Volume 或 Bind Mount。
Docker 只能跑 Linux 吗?
Docker Engine 基于 Linux 内核特性(Namespaces/Cgroups),所以:
- Linux:原生支持
- macOS/Windows:通过 Docker Desktop(基于轻量 Linux VM)运行
- 容器内的应用可以是任何语言(Node.js/Python/Go/Java 等)
镜像太大了怎么优化?
- 使用轻量基础镜像(Alpine 或 distroless)
- 多阶段构建(Multi-stage)
- .dockerignore 排除不需要的文件(node_modules/.git)
- 合并 RUN 指令减少层数
详见 Dockerfile 最佳实践。
相关阅读
- Docker vs Kubernetes 对比与选型
- Dockerfile 最佳实践
- Docker Compose 多容器编排指南
- Docker 部署 React / Next.js
- Docker 部署 Node.js
- Docker 专题导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。