为什么要学 Docker?
你有没有遇到过这些场景:
- GitHub 上找到一个很棒的开源项目,README 说「docker-compose up -d 即可部署」
- 想试一下某个工具,但安装依赖配环境搞了 2 小时还没跑起来
- 在开发机器上跑得好好的程序,部署到服务器就报错
- 想同时跑多个版本的服务(比如 MySQL 5.7 和 8.0),互相冲突
Docker 就是解决这些问题的。一句话总结:Docker 把软件和它的所有依赖打包成一个容器,在任何机器上都能一模一样地运行。
核心概念(5 分钟搞懂)
只需要理解 3 个概念:
| 概念 | 类比 | 说明 |
|---|---|---|
| 镜像(Image) | 安装包 | 一个只读模板,包含运行软件需要的一切(代码、运行时、库、配置) |
| 容器(Container) | 运行中的程序 | 镜像运行起来的实例,可以有多个容器来自同一个镜像 |
| Dockerfile | 配方 | 描述如何构建镜像的文本文件 |
类比理解:
- 镜像 = 一个 .exe 安装文件
- 容器 = 安装后正在运行的程序
- Dockerfile = 编写这个安装包的脚本
- Docker Hub = 应用商店(别人做好的镜像你可以直接下载用)
第一步:安装 Docker
Ubuntu / Debian
# 卸载旧版本(如果有)
sudo apt remove docker docker-engine docker.io containerd runc 2>/dev/null
# 安装依赖
sudo apt update
sudo apt install -y ca-certificates curl gnupg
# 添加 Docker 官方 GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 添加仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 让当前用户可以不用 sudo 运行 docker
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker --version
docker compose version
CentOS / RHEL
# 安装依赖
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 免 sudo
sudo usermod -aG docker $USER
Windows / macOS
下载安装 Docker Desktop,图形界面,开箱即用。
第二步:运行第一个容器
Hello World
docker run hello-world
这条命令做了什么:
- 检查本地有没有
hello-world镜像 → 没有 - 从 Docker Hub 下载
hello-world镜像 - 用这个镜像创建一个容器并运行
- 容器输出欢迎信息后退出
运行一个 Web 服务
docker run -d -p 8080:80 --name my-nginx nginx
参数解释:
| 参数 | 含义 |
|---|---|
-d |
后台运行(detached mode) |
-p 8080:80 |
端口映射:本机 8080 → 容器内 80 |
--name my-nginx |
给容器取个名字 |
nginx |
使用的镜像名 |
打开浏览器访问 http://localhost:8080,看到 Nginx 欢迎页面。
常用管理命令
# 查看所有运行中的容器
docker ps
# 查看所有容器(含已停止的)
docker ps -a
# 停止容器
docker stop my-nginx
# 启动已停止的容器
docker start my-nginx
# 重启容器
docker restart my-nginx
# 删除容器(必须先停止)
docker rm my-nginx
# 查看容器日志
docker logs my-nginx
# 进入容器内部(像 SSH 进去一样)
docker exec -it my-nginx /bin/bash
# 查看容器资源占用
docker stats
第三步:理解数据持久化
容器被删除后,里面的数据也会消失。用 Volume(数据卷) 把数据保存到宿主机:
# 创建命名卷
docker volume create my-data
# 运行容器并挂载卷
docker run -d \
--name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-v my-data:/var/lib/mysql \
mysql:8.0
# 即使删除容器,数据卷中的数据仍然保留
docker rm -f my-mysql
docker run -d \
--name my-mysql-2 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-v my-data:/var/lib/mysql \
mysql:8.0
# 新容器能读到之前的数据
绑定挂载(直接映射宿主机目录):
docker run -d \
--name my-nginx \
-p 80:80 \
-v /home/user/my-website:/usr/share/nginx/html:ro \
nginx
这样修改宿主机 /home/user/my-website 目录的文件,Nginx 会实时反映。
第四步:Docker Compose — 一键启动多个服务
实际项目中通常需要多个服务配合(Web + 数据库 + 缓存 + ...)。Docker Compose 用一个 YAML 文件定义和启动所有服务。
4.1 创建 docker-compose.yml
# docker-compose.yml
version: '3.8'
services:
# Web 应用
app:
image: node:20
working_dir: /app
volumes:
- ./app:/app
command: npm start
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
# 数据库
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pg-data:/var/lib/postgresql/data
ports:
- "5432:5432"
# 缓存
cache:
image: redis:7-alpine
ports:
- "6379:6379"
# 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
volumes:
pg-data:
4.2 常用 Compose 命令
# 启动所有服务(后台运行)
docker compose up -d
# 查看运行状态
docker compose ps
# 查看日志
docker compose logs -f # 所有服务
docker compose logs -f app # 指定服务
# 停止所有服务
docker compose down
# 停止并删除数据卷(⚠️ 会清除数据库数据)
docker compose down -v
# 重新构建并启动
docker compose up -d --build
# 只启动特定服务
docker compose up -d db cache
第五步:实战 — 一键部署常见开源项目
5.1 WordPress + MySQL
# docker-compose.yml
version: '3.8'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_password
WORDPRESS_DB_NAME: wordpress
volumes:
- wp-data:/var/www/html
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_password
MYSQL_ROOT_PASSWORD: root_password
volumes:
- db-data:/var/lib/mysql
volumes:
wp-data:
db-data:
mkdir wordpress && cd wordpress
# 粘贴上面的 docker-compose.yml
docker compose up -d
# 访问 http://localhost:8080 完成 WordPress 安装
5.2 Gitea(轻量级 Git 托管)
version: '3.8'
services:
gitea:
image: gitea/gitea:latest
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000" # Web UI
- "2222:22" # SSH
restart: always
volumes:
gitea-data:
5.3 Uptime Kuma(服务监控)
version: '3.8'
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
volumes:
- kuma-data:/app/data
ports:
- "3001:3001"
restart: always
volumes:
kuma-data:
5.4 N8N(工作流自动化)
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n
environment:
- N8N_HOST=localhost
- N8N_PORT=5678
- WEBHOOK_URL=http://localhost:5678/
volumes:
- n8n-data:/home/node/.n8n
ports:
- "5678:5678"
restart: always
volumes:
n8n-data:
5.5 万能模板 — 部署任何有 Docker 镜像的项目
# 1. 在 Docker Hub 搜索镜像
docker search 项目名
# 2. 查看镜像的文档(通常有 docker-compose.yml 示例)
# 访问 https://hub.docker.com/r/官方镜像名
# 3. 创建目录
mkdir my-project && cd my-project
# 4. 创建 docker-compose.yml(参考官方文档)
# 5. 启动
docker compose up -d
# 6. 查看日志确认启动成功
docker compose logs -f
第六步:Dockerfile — 打包你自己的应用
当你需要把自己的项目做成 Docker 镜像时,需要写 Dockerfile。
6.1 Node.js 项目示例
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 生产阶段(多阶段构建,最终镜像更小)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]
6.2 Python 项目示例
FROM python:3.12-slim
WORKDIR /app
# 先复制依赖文件(利用 Docker 缓存层)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 再复制代码
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
6.3 构建和运行
# 构建镜像
docker build -t my-app:latest .
# 运行
docker run -d -p 3000:3000 --name my-app my-app:latest
# 查看镜像大小
docker images my-app
Dockerfile 最佳实践
| 实践 | 原因 |
|---|---|
用 Alpine 版本(node:20-alpine) |
镜像体积小 5-10 倍 |
| 多阶段构建 | 最终镜像不包含构建工具和源码 |
| 先 COPY 依赖文件再 COPY 代码 | 利用 Docker 层缓存,依赖不变时跳过安装 |
用 .dockerignore 排除不需要的文件 |
减小构建上下文,排除 node_modules 等 |
| 不用 root 用户运行 | 安全最佳实践 |
固定版本号(postgres:16 而非 postgres:latest) |
避免意外升级导致不兼容 |
.dockerignore 示例
node_modules
.git
.gitignore
*.md
.env
.env.*
dist
coverage
.vscode
.DS_Store
常用运维命令速查
# 清理无用资源
docker system prune # 删除停止的容器、未使用的网络
docker system prune -a # 加上未使用的镜像
docker system prune -a --volumes # 加上未使用的卷(⚠️ 确认数据不需要)
# 查看资源占用
docker stats # 实时容器资源使用
docker system df # 磁盘占用概览
# 导出/导入镜像(离线传输)
docker save my-app:latest | gzip > my-app.tar.gz
gunzip -c my-app.tar.gz | docker load
# 进入容器调试
docker exec -it container_name /bin/sh # Alpine 用 sh
docker logs -f container_name # 实时看日志
docker inspect container_name # 查看详细信息(IP、挂载等)
# 限制容器资源
docker run -m 512m --cpus=1 my-app # 限制内存 512MB + 1 CPU
常见问题
Q:Docker 和虚拟机有什么区别? A:虚拟机模拟整台硬件+操作系统,启动慢(分钟级)、占资源大(GB 级)。Docker 容器共享宿主机内核,启动快(秒级)、占资源小(MB 级)。Docker 不是虚拟机的替代品,但在「运行服务」这个场景下几乎总是更好的选择。
Q:容器数据丢了怎么办? A:一定要用 Volume 或 Bind Mount 持久化重要数据。没有挂载卷的容器删除后数据不可恢复。
Q:怎么更新容器? A:
docker compose pull # 拉取最新镜像
docker compose up -d # 用新镜像重建容器
docker image prune -f # 清理旧镜像
Q:国内拉取镜像很慢怎么办?
A:配置 Docker 镜像加速器。编辑 /etc/docker/daemon.json:
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.m.daocloud.io"
]
}
然后 sudo systemctl restart docker。
参考来源: