Docker 完全指南:从入门到实践
Docker 简介
什么是 Docker?
Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中。容器是一种标准化的软件单元,可以在任何支持 Docker 的环境中运行,无论是开发者的笔记本电脑、测试服务器还是生产环境的云平台。
Docker 由 Docker Inc.(前身为 dotCloud)于 2013 年发布,基于 Go 语言开发,并利用 Linux 内核的多项特性(如 cgroups、namespaces)来实现容器的隔离和资源管理。
Docker 架构
Docker 采用客户端-服务器(C/S)架构:
┌─────────────────────────────────────────────────────────────┐
│ Docker 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────────────────────┐ │
│ │ Docker │ REST │ Docker Daemon │ │
│ │ Client │◄──────►│ (dockerd) │ │
│ │ (docker) │ API │ │ │
│ └─────────────┘ └──────────┬──────────────────┘ │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Container│ │ Container│ │ Image │ │
│ │ 1 │ │ 2 │ │ Registry│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘- Docker Client(docker):用户与 Docker 交互的主要方式,通过命令行工具发送命令
- Docker Daemon(dockerd):后台服务,负责管理 Docker 对象(镜像、容器、网络、卷等)
- Docker Registry:存储 Docker 镜像的仓库,Docker Hub 是官方的公共仓库
容器 vs 虚拟机
| 特性 | Docker 容器 | 虚拟机 |
|---|---|---|
| 启动时间 | 秒级 | 分钟级 |
| 硬盘占用 | MB 级别 | GB 级别 |
| 性能 | 接近原生 | 弱于原生 |
| 系统支持量 | 单机支持上千个容器 | 一般几十个 |
| 隔离性 | 进程级别 | 系统级别(更强) |
| 操作系统 | 共享宿主机内核 | 独立操作系统 |
Docker 的意义与价值
1. 解决“在我电脑上能运行“的问题
传统开发中,开发、测试、生产环境的差异经常导致“在我电脑上能运行“的尴尬局面。Docker 通过将应用及其所有依赖打包在一起,确保了环境的一致性。
2. 简化部署流程
# 传统部署方式
# Docker 部署方式
&& 3. 提高资源利用率
容器共享宿主机的操作系统内核,不需要为每个应用分配独立的操作系统资源,大大提高了服务器的资源利用率。
4. 支持微服务架构
Docker 天然支持微服务架构,每个微服务可以独立打包、部署、扩展,降低了服务间的耦合度。
5. 快速扩展和回滚
# 快速扩展到 5 个实例
# 快速回滚到上一版本
6. 持续集成/持续部署 (CI/CD)
Docker 与 CI/CD 工具(如 Jenkins、GitLab CI、GitHub Actions)完美集成,实现自动化构建、测试和部署。
Docker 安装
macOS 安装
推荐使用 Docker Desktop for Mac:
# 使用 Homebrew 安装
# 或者从官网下载
# https://www.docker.com/products/docker-desktop安装完成后,启动 Docker Desktop 应用程序。
Ubuntu/Debian 安装
# 1. 更新包索引并安装依赖
# 2. 添加 Docker 官方 GPG 密钥
|
# 3. 添加 Docker 仓库
|
# 4. 安装 Docker Engine
# 5. 验证安装
CentOS/RHEL 安装
# 1. 移除旧版本
# 2. 安装依赖
# 3. 添加 Docker 仓库
# 4. 安装 Docker Engine
# 5. 启动 Docker 服务
# 6. 验证安装
配置非 root 用户使用 Docker
# 创建 docker 组(如果不存在)
# 将当前用户添加到 docker 组
# 激活组更改(需要重新登录或运行以下命令)
# 验证(无需 sudo)
配置 Docker 镜像加速(中国大陆用户)
编辑或创建 /etc/docker/daemon.json:
重启 Docker 服务:
Docker 核心概念
镜像 (Image)
镜像是一个只读的模板,包含创建 Docker 容器的指令。镜像采用分层存储的方式,每一层都是对上一层的修改。
# 查看本地镜像
# 输出示例
容器 (Container)
容器是镜像的可运行实例。可以使用 Docker API 或 CLI 创建、启动、停止、移动或删除容器。
数据卷 (Volume)
数据卷用于持久化容器产生的数据,即使容器被删除,数据卷中的数据也会保留。
网络 (Network)
Docker 网络允许容器之间以及容器与外部世界之间进行通信。
常用命令详解
镜像管理命令
docker pull - 拉取镜像
参数说明:
NAME:镜像名称TAG:镜像标签,默认为latestDIGEST:镜像摘要
示例:
# 拉取最新版 nginx
# 拉取指定版本
# 拉取指定摘要的镜像
docker images - 列出镜像
常用参数:
| 参数 | 说明 |
|---|---|
-a, --all | 显示所有镜像(包括中间层) |
-q, --quiet | 只显示镜像 ID |
--filter | 根据条件过滤 |
--format | 自定义输出格式 |
示例:
# 列出所有镜像
# 只显示镜像 ID
# 过滤悬空镜像
# 自定义格式输出
docker rmi - 删除镜像
常用参数:
| 参数 | 说明 |
|---|---|
-f, --force | 强制删除 |
--no-prune | 不删除未标记的父镜像 |
示例:
# 删除指定镜像
# 强制删除
# 删除所有悬空镜像
# 删除所有未使用的镜像
docker build - 构建镜像
| | 常用参数:
| 参数 | 说明 |
|---|---|
-t, --tag | 为镜像打标签 |
-f, --file | 指定 Dockerfile 路径 |
--build-arg | 设置构建时变量 |
--no-cache | 不使用缓存 |
--platform | 指定目标平台 |
示例:
# 基本构建
# 指定 Dockerfile
# 传递构建参数
# 多平台构建
容器管理命令
docker run - 创建并启动容器
常用参数详解:
| 参数 | 说明 | 示例 |
|---|---|---|
-d, --detach | 后台运行容器 | docker run -d nginx |
-p, --publish | 端口映射 (主机端口:容器端口) | docker run -p 8080:80 nginx |
-P, --publish-all | 随机映射所有暴露端口 | docker run -P nginx |
-v, --volume | 挂载数据卷 | docker run -v /host/path:/container/path nginx |
--mount | 更详细的挂载选项 | docker run --mount type=bind,src=/host,dst=/container nginx |
-e, --env | 设置环境变量 | docker run -e MYSQL_ROOT_PASSWORD=123456 mysql |
--env-file | 从文件读取环境变量 | docker run --env-file .env myapp |
--name | 为容器命名 | docker run --name my-nginx nginx |
--network | 指定网络 | docker run --network my-network nginx |
--restart | 重启策略 | docker run --restart=always nginx |
-it | 交互式终端 | docker run -it ubuntu /bin/bash |
--rm | 容器退出时自动删除 | docker run --rm nginx |
-m, --memory | 内存限制 | docker run -m 512m nginx |
--cpus | CPU 限制 | docker run --cpus 1.5 nginx |
-w, --workdir | 工作目录 | docker run -w /app myapp |
-u, --user | 指定用户 | docker run -u 1000:1000 myapp |
常用示例:
# 后台运行 nginx,映射 80 端口
# 运行 MySQL,设置密码和持久化数据
# 运行临时容器进行调试
# 带资源限制运行容器
docker ps - 列出容器
常用参数:
| 参数 | 说明 |
|---|---|
-a, --all | 显示所有容器(包括已停止的) |
-q, --quiet | 只显示容器 ID |
-n, --last | 显示最近创建的 n 个容器 |
-l, --latest | 显示最近创建的容器 |
--filter | 根据条件过滤 |
--format | 自定义输出格式 |
示例:
# 查看运行中的容器
# 查看所有容器
# 只显示容器 ID
# 过滤特定状态的容器
# 自定义格式
docker start/stop/restart - 容器生命周期管理
# 启动一个或多个已停止的容器
# 停止一个或多个运行中的容器
# 重启容器
常用参数:
| 参数 | 说明 |
|---|---|
-t, --time | 等待停止的超时时间(秒) |
示例:
# 启动容器
# 停止容器(默认等待 10 秒)
# 立即停止容器
# 重启容器
# 停止所有运行中的容器
docker rm - 删除容器
常用参数:
| 参数 | 说明 |
|---|---|
-f, --force | 强制删除运行中的容器 |
-v, --volumes | 同时删除关联的数据卷 |
示例:
# 删除已停止的容器
# 强制删除运行中的容器
# 删除所有已停止的容器
# 删除所有容器(包括运行中的)
docker logs - 查看容器日志
常用参数:
| 参数 | 说明 |
|---|---|
-f, --follow | 跟踪日志输出(类似 tail -f) |
--tail | 显示最后 n 行 |
-t, --timestamps | 显示时间戳 |
--since | 显示指定时间之后的日志 |
--until | 显示指定时间之前的日志 |
示例:
# 查看所有日志
# 实时跟踪日志
# 查看最后 100 行
# 显示时间戳
# 查看最近 1 小时的日志
docker inspect - 查看详细信息
|示例:
# 查看容器详细信息
# 查看容器 IP 地址
# 查看容器挂载信息
| 网络管理命令
# 创建网络
# 列出网络
# 查看网络详情
# 连接容器到网络
# 断开容器与网络的连接
# 删除网络
数据卷管理命令
# 创建数据卷
# 列出数据卷
# 查看数据卷详情
# 删除数据卷
# 删除所有未使用的数据卷
进入容器终端
docker exec - 在运行中的容器内执行命令
常用参数:
| 参数 | 说明 |
|---|---|
-i, --interactive | 保持 STDIN 打开 |
-t, --tty | 分配一个伪终端 |
-d, --detach | 后台运行命令 |
-e, --env | 设置环境变量 |
-u, --user | 指定用户 |
-w, --workdir | 指定工作目录 |
示例:
# 进入容器的 bash 终端
# 进入容器的 sh 终端(适用于 Alpine 等轻量镜像)
# 以 root 用户进入容器
# 在容器内执行单个命令
# 在后台执行命令
# 设置环境变量执行命令
docker attach - 附加到运行中的容器
注意: attach 连接的是容器的主进程(PID 1),退出时可能会导致容器停止。使用 Ctrl+P Ctrl+Q 可以在不停止容器的情况下分离。
# 附加到容器
# 分离快捷键:Ctrl+P Ctrl+Qdocker exec vs docker attach 对比
| 特性 | docker exec | docker attach |
|---|---|---|
| 创建新进程 | 是 | 否 |
| 可执行任意命令 | 是 | 否 |
| 退出影响容器 | 不影响 | 可能停止容器 |
| 使用场景 | 调试、运维 | 查看主进程输出 |
Dockerfile 详解
Dockerfile 是什么?
Dockerfile 是一个文本文件,包含了构建 Docker 镜像所需的所有指令。Docker 通过读取 Dockerfile 中的指令自动构建镜像。
Dockerfile 指令详解
FROM - 基础镜像
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]说明: 指定基础镜像,必须是 Dockerfile 的第一条指令。
# 使用官方 Node.js 镜像
FROM node:18-alpine
# 多阶段构建
FROM golang:1.21 AS builder
FROM alpine:3.18 AS runtimeLABEL - 元数据
LABEL <key>=<value> <key>=<value> ...LABEL maintainer="your@email.com"
LABEL version="1.0"
LABEL description="My awesome application"ENV - 环境变量
ENV <key>=<value> ...ENV NODE_ENV=production
ENV APP_HOME=/app \
APP_PORT=3000ARG - 构建参数
ARG <name>[=<default value>]说明: 定义构建时的变量,只在构建阶段有效。
ARG VERSION=1.0
ARG BUILD_DATE
# 使用构建参数
RUN echo "Building version ${VERSION}"构建时传递参数:
WORKDIR - 工作目录
WORKDIR /path/to/workdirWORKDIR /app
# 后续的 RUN、CMD、COPY 等指令都在 /app 目录下执行COPY - 复制文件
COPY [--chown=<user>:<group>] <src>... <dest># 复制单个文件
COPY package.json .
# 复制多个文件
COPY package.json package-lock.json ./
# 复制目录
COPY src/ ./src/
# 设置文件所有者
COPY --chown=node:node . .ADD - 添加文件
ADD [--chown=<user>:<group>] <src>... <dest>说明: 与 COPY 类似,但支持自动解压压缩文件和远程 URL。
# 自动解压 tar 文件
ADD archive.tar.gz /app
# 从 URL 下载文件
ADD https://example.com/file.txt /app/最佳实践: 除非需要自动解压功能,否则优先使用 COPY。
RUN - 执行命令
# Shell 形式
RUN <command>
# Exec 形式
RUN ["executable", "param1", "param2"]# 安装依赖
RUN apt-get update && apt-get install -y \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
# 多条命令合并(减少层数)
RUN npm install && \
npm run build && \
npm prune --productionCMD - 容器启动命令
# Exec 形式(推荐)
CMD ["executable", "param1", "param2"]
# Shell 形式
CMD command param1 param2
# 作为 ENTRYPOINT 的默认参数
CMD ["param1", "param2"]# 启动 Node.js 应用
CMD ["node", "server.js"]
# 启动 nginx
CMD ["nginx", "-g", "daemon off;"]注意: Dockerfile 中只能有一条 CMD 指令,如果有多条,只有最后一条生效。
ENTRYPOINT - 入口点
# Exec 形式(推荐)
ENTRYPOINT ["executable", "param1", "param2"]
# Shell 形式
ENTRYPOINT command param1 param2# 定义入口点
ENTRYPOINT ["python", "app.py"]
# 配合 CMD 使用
ENTRYPOINT ["python"]
CMD ["app.py"] # 可以被 docker run 的参数覆盖EXPOSE - 暴露端口
EXPOSE <port> [<port>/<protocol>...]# 暴露 HTTP 端口
EXPOSE 80
# 暴露多个端口
EXPOSE 80 443
# 指定协议
EXPOSE 80/tcp
EXPOSE 53/udp注意: EXPOSE 只是声明端口,实际发布端口需要在运行时使用 -p 参数。
VOLUME - 数据卷
VOLUME ["/data"]# 声明数据卷
VOLUME /var/lib/mysql
VOLUME ["/data", "/logs"]USER - 切换用户
USER <user>[:<group>]# 创建用户并切换
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 或使用 UID:GID
USER 1000:1000HEALTHCHECK - 健康检查
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE # 禁用健康检查选项:
| 选项 | 默认值 | 说明 |
|---|---|---|
--interval | 30s | 检查间隔 |
--timeout | 30s | 超时时间 |
--start-period | 0s | 启动等待时间 |
--retries | 3 | 失败重试次数 |
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# 对于非 HTTP 服务
HEALTHCHECK --interval=30s --timeout=3s \
CMD pg_isready -U postgres || exit 1SHELL - 默认 Shell
SHELL ["executable", "parameters"]# Windows 示例
SHELL ["powershell", "-Command"]
# Linux 示例
SHELL ["/bin/bash", "-c"]完整 Dockerfile 示例
Node.js 应用
# 使用官方 Node.js Alpine 镜像
FROM node:18-alpine
# 设置元数据
LABEL maintainer="developer@example.com"
LABEL version="1.0.0"
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装依赖(生产环境)
RUN npm ci --only=production
# 复制源代码
COPY . .
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# 启动命令
CMD ["node", "server.js"]Go 应用(多阶段构建)
# ==================== 构建阶段 ====================
FROM golang:1.21-alpine AS builder
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY go.mod go.sum ./
# 下载依赖
RUN go mod download
# 复制源代码
COPY . .
# 构建二进制文件
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# ==================== 运行阶段 ====================
FROM alpine:3.18
# 安装 CA 证书(用于 HTTPS 请求)
RUN apk --no-cache add ca-certificates
# 设置工作目录
WORKDIR /root/
# 从构建阶段复制二进制文件
COPY --from=builder /app/main .
# 复制配置文件
COPY --from=builder /app/config ./config
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# 启动命令
CMD ["./main"]Python 应用
FROM python:3.11-slim
# 避免 Python 缓冲输出
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制源代码
COPY . .
# 创建非 root 用户
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"].dockerignore 文件
类似于 .gitignore,用于排除不需要复制到镜像中的文件:
# Git
.git
.gitignore
# Node.js
node_modules
npm-debug.log
# Python
__pycache__
*.pyc
.venv
venv
# IDE
.idea
.vscode
*.swp
# Build
dist
build
*.log
# Docker
Dockerfile*
docker-compose*.yml
# 其他
.env
.env.local
README.md
docs/
tests/生成自定义镜像
使用 docker build 构建
# 基本构建
# 指定 Dockerfile
# 不使用缓存
# 多平台构建
使用 docker commit 从容器创建镜像
# 从运行中的容器创建镜像
常用参数:
| 参数 | 说明 |
|---|---|
-a, --author | 作者 |
-m, --message | 提交信息 |
-c, --change | 应用 Dockerfile 指令 |
示例:
# 启动基础容器
# 在容器内安装软件
&&
# 退出容器
# 从容器创建镜像
注意: 推荐使用 Dockerfile 构建镜像,因为它更加透明、可重复和易于维护。
镜像标签管理
# 添加标签
# 查看镜像标签
推送镜像到仓库
推送到 Docker Hub
# 1. 登录 Docker Hub
# 输入用户名和密码
# 2. 为镜像打标签(必须包含用户名)
# 3. 推送镜像
# 4. 推送所有标签
推送到私有仓库
# 1. 登录私有仓库
# 2. 为镜像打标签
# 3. 推送镜像
推送到阿里云容器镜像服务
# 1. 登录阿里云镜像仓库
# 2. 为镜像打标签
# 3. 推送镜像
推送到 GitHub Container Registry
# 1. 创建 Personal Access Token (PAT)
# 在 GitHub Settings > Developer settings > Personal access tokens
# 2. 登录
|
# 3. 为镜像打标签
# 4. 推送镜像
Docker Compose 简介
Docker Compose 是用于定义和运行多容器 Docker 应用程序的工具。
安装 Docker Compose
Docker Desktop 已包含 Docker Compose。对于 Linux:
# 使用包管理器安装(推荐)
# 验证安装
docker-compose.yml 示例
version: '3.8'
services:
# Web 应用
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://postgres:password@db:5432/myapp
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
- app-network
# 数据库
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test:
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Redis 缓存
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- app-network
# Nginx 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- web
networks:
- app-network
volumes:
postgres-data:
redis-data:
networks:
app-network:
driver: bridgeDocker Compose 常用命令
# 启动所有服务
# 后台启动
# 构建并启动
# 停止所有服务
# 停止并删除数据卷
# 查看服务日志
# 查看服务状态
# 进入服务容器
# 扩展服务实例
最佳实践
1. 镜像构建最佳实践
- 使用官方基础镜像:选择官方维护的镜像作为基础
- 选择精简镜像:优先使用 Alpine 或 Distroless 镜像
- 使用多阶段构建:分离构建环境和运行环境
- 减少层数:合并 RUN 指令
- 合理利用缓存:将变化频率低的指令放在前面
2. 安全最佳实践
# 使用非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 只复制必要的文件
COPY --chown=appuser:appgroup . .
# 使用特定版本而非 latest
FROM node:18.19.0-alpine
# 定期更新基础镜像
# 扫描镜像漏洞
docker scout cves myapp:latest3. 性能优化
# 合并 RUN 命令减少层数
RUN apt-get update && apt-get install -y \
package1 \
package2 \
&& rm -rf /var/lib/apt/lists/*
# 先复制依赖文件,再复制源代码
COPY package*.json ./
RUN npm install
COPY . .
# 使用 .dockerignore 排除不必要的文件4. 日志管理
# 配置日志驱动
5. 资源限制
# 限制内存和 CPU
参考资料
官方文档
- Docker 官方文档 - Docker 完整文档
- Docker Hub - Docker 官方镜像仓库
- Dockerfile 参考 - Dockerfile 指令完整参考
- Docker Compose 文档 - Docker Compose 使用指南
学习资源
- Docker 入门教程 - 菜鸟教程
- Docker 从入门到实践 - 开源中文教程
- Play with Docker - 在线 Docker 练习环境
工具推荐
- Docker Desktop - 桌面版 Docker 管理工具
- Portainer - Docker 可视化管理工具
- Dive - Docker 镜像分析工具
- Hadolint - Dockerfile 静态分析工具
相关技术
- Kubernetes 官方文档 - 容器编排平台
- Docker Swarm - Docker 原生集群管理
- containerd - 容器运行时
本文更新日期:2024年12月
如果这篇文章对你有帮助,欢迎点赞和分享!有任何问题,欢迎在评论区讨论。
请先登录后再发表评论