Docker入门到精通:从零基础到生产部署
前言:为什么你需要学习Docker?
想象一下,你开发了一个应用程序,在你的电脑上运行完美,但当你把它交给同事或部署到服务器时,却出现了各种奇怪的问题。这就是著名的"在我机器上能运行"问题。
Docker就是解决这个问题的神器!它能确保你的应用在任何地方都能一致地运行,无论是在你的笔记本电脑、数据中心的服务器,还是在云平台上。
学习路径图:
本手册专为零基础小白设计,通过简单易懂的语言、实用示例和互动练习,带你从Docker小白成长为能够熟练使用Docker的开发者。
第一章:Docker基础概念
1.1 什么是Docker?
Docker是一种容器化技术,它允许你将应用程序及其所有依赖(代码、库、环境变量等)打包到一个轻量级、可移植的"容器"中。
类比理解:
┌──────────────────────────────────────┐
│ 宿主机操作系统 │
├───────────┬───────────┬──────────────┤
│ 容器1 │ 容器2 │ 容器3 │
│ (应用A) │ (应用B) │ (应用C) │
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │
│ │应用 │ │ │应用 │ │ │应用 │ │
│ │代码 │ │ │代码 │ │ │代码 │ │
│ └─────┘ │ └─────┘ │ └─────┘ │
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │
│ │依赖 │ │ │依赖 │ │ │依赖 │ │
│ │库 │ │ │库 │ │ │库 │ │
│ └─────┘ │ └─────┘ │ └─────┘ │
└───────────┴───────────┴──────────────┘
- 每个容器就像一艘集装箱船上的标准集装箱
- 每个集装箱(容器)都包含特定的货物(应用程序)
- 无论船(服务器)是什么类型,集装箱都能被正确装卸和运输
- 集装箱之间相互隔离,互不影响
💡 小贴士:Docker容器共享宿主机的操作系统内核,而虚拟机需要运行完整的操作系统,因此容器更轻量、启动更快。
1.2 Docker架构
Docker采用客户端-服务端架构,主要组件包括:
┌───────────────────────────────────────────────────────────────┐
│ 宿主机 │
├───────────────────┬───────────────────────────┬───────────────┤
│ Client │ Docker Daemon │ Registry │
│ (docker命令行) │ (dockerd, containerd) │ (Docker Hub) │
└─────────┬─────────┴─────────────────┬───────┴───────┬───────┘│ │ │▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Docker CLI │ │ Container Runtime│ │ Image Store │
└─────────────────┘ └──────────────────┘ └──────────────┘
- Docker CLI:命令行界面,用于向Docker守护进程发送命令
- Docker Daemon:Docker守护进程,负责管理镜像、容器、网络和卷等
- Container Runtime:容器运行时(如containerd),负责运行容器
- Registry:镜像仓库,用于存储和分发Docker镜像
1.3 Docker vs 虚拟机
特性 | Docker容器 | 虚拟机 |
---|---|---|
架构 | 直接运行在宿主机操作系统上 | 运行在Hypervisor上 |
资源占用 | 轻量级(MB级别) | 重量级(GB级别) |
启动速度 | 秒级 | 分钟级 |
隔离性 | 进程级隔离 | 完整操作系统隔离 |
性能 | 几乎无损耗 | 有性能损耗 |
关键区别:
┌───────────────────┐ ┌───────────────────┐
│ 虚拟机 │ │ Docker │
├─────────┬─────────┤ ├─────────┬─────────┤
│ Guest OS│ 应用 │ │ 应用 │ 依赖 │
├─────────┼─────────┤ ├─────────┼─────────┤
│ Hypervisor │ │ Docker │ │
├─────────┼─────────┤ ├─────────┼─────────┤
│ Host OS │ │ │ Host OS │ │
└─────────┴─────────┘ └─────────┴─────────┘
1.4 Docker核心概念
镜像(Image)
- Docker的"蓝图"或"模板"
- 包含运行应用程序所需的一切
- 只读层,不可修改
容器(Container)
- 镜像的运行实例
- 镜像 + 可写层
- 应用程序实际运行的地方
仓库(Repository)
- 存储Docker镜像的地方
- 最常用的公共仓库:Docker Hub
Docker Hub上最受欢迎的镜像:
- 数据库:
- PostgreSQL(1B+ pulls,14502 stars)
- MySQL(1B+ pulls,15899 stars)
- MongoDB(1B+ pulls,10623 stars)
- 开发环境:
- Node.js(1B+ pulls,13983 stars)
- OpenJDK(1B+ pulls,4067 stars)
- Golang(1B+ pulls,5063 stars)
- PHP(1B+ pulls,7790 stars)
Dockerfile
- 创建Docker镜像的"配方"
- 包含一系列指令
💡 避坑指南:镜像是静态的,容器是动态的。你可以从同一个镜像启动多个容器实例。
1.5 Docker Engine更新渠道
Docker Engine提供两种更新渠道:
- Stable(稳定版):经过充分测试的正式发布版本
- Test(测试版):预发布版本,用于测试新功能
生产环境建议使用Stable渠道,开发环境可考虑使用Test渠道体验新功能。
第二章:安装Docker
2.1 Windows系统安装
-
下载Docker Desktop:
- 访问 Docker官网
- 点击"Download for Windows"
-
安装过程:
- 双击下载的安装文件
- 按照向导提示进行安装
- 建议勾选"Install required Windows components for WSL 2"
-
启动Docker:
- 安装完成后,Docker会自动启动
- 检查系统托盘,看到鲸鱼图标表示Docker正在运行
-
验证安装:
在命令提示符或PowerShell中输入:
> docker --version Docker version 24.0.7, build afdd53b
💡 小贴士:Windows 10家庭版需要额外安装WSL 2(Windows Subsystem for Linux 2)。安装后可能需要重启电脑。
许可说明:Docker Desktop 对于个人用户、教育机构和中小型企业是免费的。大型企业(超过250名员工或年收入超过1000万美元)需要购买商业许可。
2.2 macOS系统安装
-
下载Docker Desktop:
- 访问 Docker官网
- 点击"Download for Mac"
-
安装过程:
- 双击下载的
.dmg
文件 - 将Docker图标拖到Applications文件夹
- 在Applications中双击Docker.app启动
- 双击下载的
-
验证安装:
在终端中输入:
> docker --version Docker version 24.0.7, build afdd53b
2.3 Linux系统安装(Ubuntu 22.04示例)
# 1. 更新软件包索引
> sudo apt update# 2. 安装必要的软件包
> sudo apt install apt-transport-https ca-certificates curl software-properties-common# 3. 添加Docker官方GPG密钥
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg# 4. 设置Docker稳定版仓库
> echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null# 5. 安装Docker引擎
> sudo apt update
> sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# 6. 验证Docker是否正确安装
> sudo docker run hello-world
💡 避坑指南:安装后,普通用户无法直接运行Docker命令。解决方法:
> sudo usermod -aG docker $USER
> newgrp docker # 或者重启终端
注意:以上以Ubuntu为例,其他Linux发行版的安装命令请参考Docker官方安装文档。
2.4 Docker Desktop功能详解
Docker Desktop不仅包含Docker Engine,还提供了一系列增强功能:
- Docker Engine:强大的容器运行时,提供高性能和可靠的容器化应用支持
- Docker CLI:灵活的命令行界面,提供精确的容器控制
- Docker Compose:简化多容器应用的管理
- Docker Build:简化容器镜像构建过程
- Docker Kubernetes:内置Kubernetes支持,无需外部集群即可本地开发
- Volume Management:有效的数据管理解决方案
- Synchronized File Shares:实时同步主机和容器间的文件
- Docker Debug:高级故障排除工具
- Hardened Docker Desktop:增强的容器隔离和安全性
- VDI Support:虚拟桌面基础设施集成
- Docker Private Extensions Marketplace:定制化扩展功能
2.5 验证安装
无论哪个平台,安装完成后运行以下命令:
> docker run hello-world
如果看到类似以下输出,说明Docker安装成功:
Hello from Docker!
This message shows that your installation appears to be working correctly.
💡 小贴士:docker --version
只验证了客户端。docker run hello-world
验证整个Docker引擎(客户端+守护进程)都已正确安装并运行。
第三章:Docker基础操作
3.1 第一个Docker容器
让我们运行一个简单的Nginx Web服务器:
> docker run -d -p 8080:80 --name my-nginx nginx
参数解释:
-d
:后台运行容器(detached模式)-p 8080:80
:将宿主机的8080端口映射到容器的80端口--name my-nginx
:给容器命名nginx
:要使用的镜像名称(如果本地不存在,Docker会自动从Docker Hub拉取官方nginx镜像)
💡 小贴士:docker run
命令实际上融合了 docker pull
(如果镜像不存在)、docker create
、docker start
三个步骤。
验证:
- 打开浏览器
- 访问
http://localhost:8080
- 应该看到Nginx欢迎页面
3.2 常用Docker命令
容器管理
# 列出正在运行的容器
> 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# 进入正在运行的容器
> docker exec -it my-nginx bash# 查看Docker磁盘使用情况
> docker system df
镜像管理
# 列出本地镜像
> docker images# 拉取镜像(从Docker Hub)
> docker pull ubuntu:22.04# 删除镜像
> docker rmi nginx# 构建镜像(基于Dockerfile)
> docker build -t my-app:1.0 .
💡 避坑指南:删除正在运行的容器前,需要先停止它:docker stop container_id && docker rm container_id
,或者直接使用docker rm -f container_id
强制删除。
3.3 实战练习:运行Python应用
-
创建一个简单的Python应用:
> mkdir python-app > cd python-app > echo "from http.server import HTTPServer, BaseHTTPRequestHandlerclass SimpleHandler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-type', 'text/html')self.end_headers()self.wfile.write(b'Hello from Docker!')if __name__ == '__main__':server = HTTPServer(('0.0.0.0', 8000), SimpleHandler)server.serve_forever()" > app.py
-
运行Python应用容器:
> docker run -d -p 8000:8000 -v $(pwd):/app -w /app python:3.11 python app.py
-
访问
http://localhost:8000
查看结果
命令解释:
-v $(pwd):/app
:将当前目录挂载到容器的/app目录-w /app
:设置工作目录为/apppython:3.11
:使用Python 3.11官方镜像
💡 小贴士:在Windows PowerShell中,$(pwd)
应替换为${PWD}
。
📝 本章练习
- 运行一个Ubuntu容器:
docker run -it ubuntu bash
- 在容器内执行
ls /
,查看文件系统 - 退出容器(输入
exit
或按Ctrl+D) - 再次运行相同的命令,观察结果有何不同
- (挑战)运行一个MySQL容器,使用
-e MYSQL_ROOT_PASSWORD=my-secret-pw
设置root密码,并使用docker exec
命令进入容器验证MySQL是否正常运行
第四章:Dockerfile详解
4.1 什么是Dockerfile?
Dockerfile是一个文本文件,包含了一系列指令,告诉Docker如何构建一个镜像。
4.2 基本Dockerfile结构
让我们创建一个简单的Node.js应用Dockerfile:
# 1. 基础镜像
FROM node:18# 2. 设置工作目录
WORKDIR /app# 3. 复制package.json(先单独复制,利用Docker缓存)
COPY package.json .# 4. 安装依赖
RUN npm install# 5. 复制应用代码
COPY . .# 6. 暴露端口
EXPOSE 3000# 7. 定义启动命令
CMD ["npm", "start"]
4.3 关键指令详解
指令 | 用途 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM ubuntu:22.04 |
ARG | 定义构建参数 | ARG NODE_VERSION=18 FROM node:${NODE_VERSION} |
RUN | 在镜像中执行命令 | RUN apt-get update && apt-get install -y python3 |
COPY | 复制文件到镜像 | COPY app.py /app/ |
ADD | 类似COPY,但支持URL和自动解压 | ADD https://example.com/file.tar.gz /app/ |
WORKDIR | 设置工作目录 | WORKDIR /app |
ENV | 设置环境变量 | ENV NODE_ENV=production |
EXPOSE | 声明容器运行时监听的端口 | EXPOSE 80 |
CMD | 容器启动时执行的命令 | CMD ["python", "app.py"] |
ENTRYPOINT | 容器启动时执行的命令(不可覆盖) | ENTRYPOINT ["java", "-jar", "/app.jar"] |
4.4 构建和运行自定义镜像
-
创建Node.js应用:
> mkdir node-app > cd node-app > npm init -y > echo 'const express = require("express"); const app = express(); app.get("/", (req, res) => res.send("Hello from Docker!")); app.listen(3000, () => console.log("Server running on port 3000"));' > index.js
-
创建Dockerfile(内容如上所述)
-
构建镜像:
> docker build -t my-node-app:1.0 .
-
运行容器:
> docker run -d -p 3000:3000 --name node-app my-node-app:1.0
-
访问
http://localhost:3000
💡 避坑指南:Docker构建时,默认使用当前目录作为上下文。确保Dockerfile在项目根目录,且不包含不必要的大文件(使用.dockerignore)。
4.5 Docker BuildKit详解
Docker BuildKit是Docker 18.09+引入的下一代构建系统,提供了显著的性能改进和新功能:
启用BuildKit:
# 临时启用
> DOCKER_BUILDKIT=1 docker build .# 永久启用(修改daemon.json)
{"features": {"buildkit": true}
}
BuildKit优势:
- 更快的构建速度:并行构建和缓存优化
- 更好的安全性:隔离的构建环境
- 高级功能:
# 语法声明(使用BuildKit特有功能) # syntax=docker/dockerfile:1.3# SSH转发 FROM alpine RUN --mount=type=ssh ssh example.com ls# 构建时缓存 RUN --mount=type=cache,target=/root/.cache/go-build go build .# 秘密管理 RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
💡 小贴士:Docker 23.0+默认启用BuildKit,可以自动清理中间层,进一步减小镜像大小。
4.6 优化Docker镜像大小
1. 使用合适的基镜像
- 优先使用
alpine
版本(更小) - 例如:
node:18-alpine
比node:18
小约200MB
2. 多阶段构建
# 构建阶段
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 使用ci确保依赖版本确定性
COPY . .
RUN npm run build# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package.json .
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
3. 减少镜像层数
# 不推荐
RUN apt-get update
RUN apt-get install -y package1 package2# 推荐(合并为一条命令)
RUN apt-get update && apt-get install -y \package1 \package2 \&& rm -rf /var/lib/apt/lists/*
4. 清理不必要的文件
RUN npm install && npm cache clean --force
5. 使用.dockerignore文件
创建.dockerignore
文件,排除不需要的文件:
node_modules
.git
*.log
.env
Dockerfile
.dockerignore
📝 本章练习
- 为你的Python应用创建Dockerfile
- 构建并运行镜像
- 使用
docker image inspect
查看镜像详情 - (挑战)尝试使用多阶段构建优化你的Docker镜像
第五章:Docker Compose
5.1 什么是Docker Compose?
Docker Compose是用于定义和运行多容器Docker应用程序的工具。通过一个YAML文件配置应用程序服务,然后使用一个命令创建并启动所有服务。
5.2 安装Docker Compose
- Windows/macOS:Docker Desktop已包含Compose
- Linux:Docker 20.10+已内置Compose插件,无需单独安装
💡 小贴士:在Linux上,旧版Docker需要单独安装Compose:
> sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
> sudo chmod +x /usr/local/bin/docker-compose
5.3 Docker Compose Specification
Docker Compose已发展为Compose Specification,这是云原生计算基金会(CNCF)的项目,旨在标准化多容器应用的定义。最新版本已移除version
字段要求:
services:web:image: nginxports:- "8080:80"db:image: postgresenvironment:POSTGRES_PASSWORD: example
这种格式与Docker Compose、Podman Compose和Kubernetes的Kompose兼容,提供更广泛的互操作性。
5.4 docker-compose.yml结构
version: '3.8' # 指定Compose文件格式版本services: # 定义所有服务web: # 服务名称image: nginx:latest # 使用的镜像ports:- "8080:80" # 端口映射volumes:- ./html:/usr/share/nginx/html # 卷挂载db:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: example # 设置环境变量MYSQL_DATABASE: mydbvolumes:- db_data:/var/lib/mysql # 命名卷volumes: # 定义卷db_data:
💡 小贴士:对于新项目,可以直接使用Compose Specification(即直接写 services:
),这代表最新标准。工具会自动兼容。
5.5 实战:部署WordPress应用
-
创建项目目录:
> mkdir wordpress-app > cd wordpress-app
-
创建
docker-compose.yml
文件:version: '3.8'services:db:image: mysql:8.0volumes:- db_data:/var/lib/mysqlrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: somewordpressMYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD: wordpresshealthcheck: # 添加健康检查test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u$$MYSQL_USER", "-p$$MYSQL_PASSWORD"]interval: 10stimeout: 5sretries: 5wordpress:depends_on:db:condition: service_healthy # 确保数据库真正就绪image: wordpress:latestports:- "8000:80"restart: alwaysenvironment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD: wordpressWORDPRESS_DB_NAME: wordpress volumes:db_data:
-
启动应用:
> docker-compose up -d
-
访问
http://localhost:8000
开始WordPress安装 -
常用Compose命令:
# 启动所有服务 > docker-compose up -d# 停止所有服务 > docker-compose down# 查看服务日志 > docker-compose logs -f# 重启服务 > docker-compose restart wordpress# 构建/重新构建服务 > docker-compose build
⚠️ 重要提示:depends_on
只控制启动顺序,不等待服务真正就绪。对于需要等待数据库初始化的应用,必须实现健康检查并使用condition: service_healthy
,这是生产环境的最佳实践。
📝 本章练习
- 创建一个包含Nginx和Alpine的Compose文件
- 配置Nginx服务监听8080端口
- 使用
docker-compose up
启动服务 - 访问
http://localhost:8080
验证 - (挑战)为Nginx配置自定义HTML内容(使用卷挂载)
第六章:Docker网络
6.1 Docker网络模式
模式 | 描述 | 使用场景 |
---|---|---|
bridge | 默认模式,容器通过虚拟网桥连接 | 单机上多个容器通信 |
host | 容器直接使用宿主机网络 | 需要高性能网络的应用 |
none | 容器没有网络 | 完全隔离的容器 |
overlay | 跨多个Docker守护进程的网络 | Docker Swarm集群 |
6.2 创建自定义网络
# 创建自定义桥接网络
> docker network create my-network# 在自定义网络中运行容器
> docker run -d --name web --network my-network nginx
> docker run -it --name alpine --network my-network alpine sh# 在alpine容器中测试与web容器的连接
/ # ping web
6.3 容器间通信
场景:前端应用需要连接后端API
-
创建自定义网络:
> docker network create app-network
-
启动后端服务:
> docker run -d --name backend --network app-network -p 5000:5000 my-backend-image
-
启动前端服务:
> docker run -d --name frontend --network app-network -p 3000:3000 \-e API_URL=http://backend:5000 my-frontend-image
-
前端容器可以通过
http://backend:5000
访问后端服务
6.4 网络排查
# 查看所有网络
> docker network ls# 查看特定网络的详细信息
> docker network inspect app-network# 查看容器的网络配置
> docker inspect frontend | grep IPAddress
💡 避坑指南:Docker容器使用服务名称作为主机名进行通信。确保在代码中使用服务名称(如http://backend:5000
)而不是IP地址。
📝 本章练习
- 创建一个自定义网络
test-net
- 在该网络中运行两个Nginx容器
- 从一个容器ping另一个容器
- 尝试不使用自定义网络,直接通过容器名通信(会失败)
- (挑战)创建一个包含前端、后端和数据库的Compose文件,并配置正确的网络
第七章:数据持久化
7.1 为什么需要数据持久化?
默认情况下,容器停止后,容器内的所有数据都会丢失。对于数据库等需要持久存储的应用,我们需要将数据存储在容器外部。
7.2 三种数据管理方式
类型 | 描述 | 适用场景 |
---|---|---|
数据卷(Volumes) | 由Docker管理的存储区域 | 生产环境,最佳实践 |
绑定挂载(Bind Mounts) | 将宿主机目录直接挂载到容器 | 开发环境,需要实时编辑文件 |
tmpfs挂载 | 仅存储在内存中 | 临时数据,敏感数据 |
7.3 使用数据卷
# 创建命名卷
> docker volume create my-volume# 查看所有卷
> docker volume ls# 使用卷运行容器
> docker run -d -v my-volume:/app/data --name my-container nginx# 查看卷详情
> docker volume inspect my-volume# 清理未使用的卷
> docker volume prune
7.4 数据卷备份与恢复
数据卷备份:
# 创建备份容器
> docker run --rm -v my-volume:/volume -v $(pwd):/backup alpine \tar cvf /backup/backup.tar -C /volume .
数据卷恢复:
# 创建新卷
> docker volume create restore-volume# 恢复数据
> docker run --rm -v restore-volume:/volume -v $(pwd):/backup alpine \tar xvf /backup/backup.tar -C /volume
生产环境建议:
- 使用定时任务定期备份关键数据卷
- 将备份存储到安全位置(如云存储)
- 测试恢复流程,确保备份有效
- 考虑使用专业备份工具如Velero(Kubernetes环境)
7.5 实战:MySQL数据持久化
# 创建数据卷
> docker volume create mysql-data# 运行MySQL容器
> docker run -d \-v mysql-data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=my-secret-pw \--name mysql \mysql:8.0
即使容器被删除,数据仍然保留在mysql-data
卷中。
💡 避坑指南:数据卷的路径在宿主机上通常是/var/lib/docker/volumes/
,但不应直接操作这些文件,应通过Docker命令管理。
7.6 使用绑定挂载进行开发
# 将当前目录挂载到容器的/app目录
> docker run -d \-v $(pwd):/app \-w /app \node:18 \npm start
开发优势:
- 代码修改后无需重新构建镜像
- 实时看到更改效果
- 适合前端开发和热重载
📝 本章练习
- 创建一个数据卷
app-data
- 运行一个Nginx容器,将
/usr/share/nginx/html
挂载到该卷 - 在卷中创建一个
index.html
文件 - 访问Nginx服务,验证内容
- (挑战)使用绑定挂载开发一个简单的Node.js应用,实现代码热重载
第八章:实战项目 - 部署一个完整的Web应用
8.1 项目结构
my-app/
├── frontend/ # 前端代码(React)
├── backend/ # 吘端代码(Node.js)
├── docker-compose.yml
└── README.md
8.2 前端Dockerfile
# frontend/Dockerfile
# 构建阶段
FROM node:18 as build
WORKDIR /app
COPY package*.json ./
RUN npm ci # 使用ci确保依赖版本确定性
COPY . .
RUN npm run build# 生产阶段
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
8.3 后端Dockerfile
# backend/Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 生产环境只安装生产依赖
COPY . .
EXPOSE 5000
CMD ["node", "server.js"]
8.4 docker-compose.yml
version: '3.8'services:frontend:build: context: ./frontendlabels:- "org.opencontainers.image.revision=${GIT_COMMIT:-latest}" # 注入git commit信息ports:- "3000:80"depends_on:backend:condition: service_healthynetworks:- app-networkbackend:build: context: ./backendlabels:- "org.opencontainers.image.revision=${GIT_COMMIT:-latest}"ports:- "5000:5000"environment:DB_HOST: dbDB_USER: userDB_PASS: passworddepends_on:db:condition: service_healthynetworks:- app-networkhealthcheck:test: ["CMD", "curl", "-f", "http://localhost:5000/health"]interval: 30stimeout: 10sretries: 3db:image: postgres:15environment:POSTGRES_USER: userPOSTGRES_PASSWORD: passwordPOSTGRES_DB: mydbvolumes:- pgdata:/var/lib/postgresql/datanetworks:- app-networkhealthcheck:test: ["CMD-SHELL", "pg_isready -U user"]interval: 10stimeout: 5sretries: 5networks:app-network:driver: bridgevolumes:pgdata:
💡 小贴士:condition: service_healthy
确保服务真正就绪后再启动依赖服务,避免启动顺序问题。通过labels注入git commit信息便于镜像追踪。
8.5 部署步骤
-
克隆项目:
> git clone https://github.com/yourusername/my-app.git > cd my-app
-
启动应用:
> docker-compose up -d --build
-
访问应用:
- 前端:
http://localhost:3000
- 后端API:
http://localhost:5000/api
- 前端:
-
查看日志:
> docker-compose logs -f
-
停止应用:
> docker-compose down
📝 本章练习
- 创建一个简单的前后端分离应用
- 为前后端分别编写Dockerfile
- 创建docker-compose.yml文件,配置服务依赖和网络
- 实现健康检查,确保服务正确启动
- (挑战)添加Redis服务,并配置前后端使用Redis
第九章:常见问题与解决方案
9.1 容器无法启动
问题:容器启动后立即退出
原因:主进程执行完毕退出
解决方案:
- 确保
CMD
或ENTRYPOINT
指定的是长期运行的进程 - 使用
-it
参数运行容器进行调试:> docker run -it --rm my-image sh
💡 避坑指南:容器必须有一个前台进程才能保持运行。如果运行的是后台服务,需要使用-d
参数或确保命令保持前台运行。
9.2 端口冲突
问题:
Error response from daemon: driver failed programming external connectivity on endpoint...:
bind: address already in use.
解决方案:
- 更换宿主机端口:
> docker run -p 8081:80 nginx
- 停止占用端口的进程:
# Linux/Mac > lsof -i :8080# Windows > netstat -ano | findstr :8080
9.3 镜像拉取失败
问题:
Error response from daemon: Get https://registry-1.docker.io/v2/:
net/http: request canceled while waiting for connection
解决方案:
- 检查网络连接
- 配置Docker镜像加速器(针对中国用户):
- 创建或修改
/etc/docker/daemon.json
- 添加:
{"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn","https://hub-mirror.c.163.com"] }
- 重启Docker:
sudo systemctl restart docker
- 创建或修改
💡 小贴士:Docker Desktop用户可以在设置中直接配置镜像加速器。常用的镜像加速器包括:
- 阿里云容器镜像服务(需登录获取个人加速地址)
- 网易云:
https://hub-mirror.c.163.com
- 中国科学技术大学:
https://docker.mirrors.ustc.edu.cn
9.4 容器内无法访问网络
问题:容器内无法ping通外部网络
解决方案:
- 检查DNS配置:
> docker run --dns=8.8.8.8 -it ubuntu ping google.com
- 检查防火墙设置
- 重置Docker网络:
> docker network prune
9.5 清理磁盘空间
问题:Docker占用大量磁盘空间
解决方案:
# 清理停止的容器
> docker container prune# 清理未使用的镜像
> docker image prune# 清理未使用的网络
> docker network prune# 清理所有未使用的资源(包括构建缓存)
> docker system prune -a# 查看磁盘使用情况
> docker system df
💡 避坑指南:定期清理可以避免磁盘空间不足问题。建议在CI/CD管道中添加清理步骤。
📝 本章练习
- 故意制造一个端口冲突,然后解决它
- 模拟镜像拉取失败,配置镜像加速器
- 创建一个无法启动的容器,使用
-it
调试 - (挑战)编写一个脚本,每天自动清理Docker资源
第十章:最佳实践与安全建议
10.1 镜像构建最佳实践
-
使用.dockerignore文件:
node_modules .git *.log .env Dockerfile .dockerignore
-
合理排序Dockerfile指令:
- 将变化较少的指令放在前面
- 例如:先COPY package.json,再RUN npm install,最后COPY其他文件
-
使用多阶段构建:
- 减小最终镜像大小
- 避免将构建工具包含在生产镜像中
-
指定软件包版本:
RUN apt-get install -y python3=3.10.6-1ubuntu0.1
-
镜像分层原理:
- Docker镜像由多层只读层组成
- 每条Dockerfile指令创建一个新层
- 利用缓存机制:当某一层发生变化时,其后的所有层都需要重新构建
- 合并相关操作到同一层可减少镜像层数
10.2 安全最佳实践
-
不要以root用户运行容器:
FROM node:18 RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser
-
定期更新基础镜像:
> docker pull node:18 > docker build -t my-app:latest .
-
扫描镜像漏洞:
# 需要先登录Docker Hub > docker login > docker scan my-app:latest# 或者使用开源工具如Trivy > trivy image --severity CRITICAL,HIGH my-app:latest
-
限制容器资源:
> docker run -d \--memory=512m \--cpus=1.5 \my-app
-
不要在镜像中存储敏感信息:
- 使用环境变量或Docker secrets
- 通过
docker run -e
或docker-compose
的environment设置
-
使用非最新版本的具体标签:
- 使用
node:18.18.0-alpine
而不是node:18-alpine
或node:latest
- 确保部署的确定性和安全性
- 使用
-
最小权限原则:
> docker run --cap-drop ALL --cap-add NET_BIND_SERVICE my-app
-
Docker内容信任(Docker Content Trust):
# 启用内容信任 > export DOCKER_CONTENT_TRUST=1# 签名并推送镜像 > docker trust sign myimage:tag# 验证签名 > docker trust inspect myimage:tag
-
安全上下文配置:
services:app:# ...security_opt:- no-new-privileges:trueread_only: truecap_drop:- ALLcap_add:- NET_BIND_SERVICE
10.3 生产环境部署建议
-
使用编排工具:
- Docker Swarm(内置)
- Kubernetes(更强大,适合大型部署)
-
实现健康检查:
HEALTHCHECK --interval=30s --timeout=3s \CMD curl -f http://localhost/ || exit 1
-
集中式日志管理:
- 使用ELK栈(Elasticsearch, Logstash, Kibana)
- 或Docker日志驱动:
docker run --log-driver=json-file ...
-
监控与告警:
- Prometheus + Grafana
- cAdvisor(容器资源监控)
-
Docker Desktop的Kubernetes集成:
Docker Desktop内置了Kubernetes支持,无需额外安装即可在本地开发环境中使用Kubernetes:-
启用Kubernetes:
- Windows/macOS:Docker Desktop设置 → Kubernetes → 勾选"Enable Kubernetes"
- Linux:需单独安装
-
验证安装:
> kubectl cluster-info Kubernetes control plane is running at https://kubernetes.docker.internal:6443
-
使用Kubernetes:
> kubectl create deployment nginx --image=nginx > kubectl expose deployment nginx --port=80 > kubectl get pods
Docker Desktop的Kubernetes支持包括:
- 单节点集群(开发使用)
- 与Docker Compose的集成
- 简单的UI管理
- 本地开发的理想环境
-
💡 避坑指南:生产环境应避免使用latest
标签,而应使用具体的版本号,确保可重复部署。
📝 本章练习
- 为你的应用Dockerfile添加非root用户
- 添加健康检查指令
- 限制容器的内存和CPU使用
- (挑战)使用Docker扫描工具检查你的镜像漏洞
第十一章:进阶主题
11.1 Docker Swarm简介
Docker Swarm是Docker原生的集群管理和编排工具。
基本概念:
- Node:集群中的Docker主机
- Manager:管理集群的节点
- Worker:执行任务的节点
- Service:在集群中运行的应用
创建Swarm集群:
# 初始化Swarm(作为Manager)
> docker swarm init# 获取加入令牌
> docker swarm join-token worker# 在其他节点上加入Swarm
> docker swarm join --token <token> <manager-ip>:2377
部署服务:
> docker service create --replicas 3 -p 80:80 --name my-web nginx
11.2 Kubernetes简介
Kubernetes(简称K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用。
核心概念:
- Pod:Kubernetes中最小的部署单元,可包含一个或多个容器
- Deployment:管理Pod的声明式更新
- Service:定义Pod的访问策略
- Namespace:资源的虚拟集群
简单示例:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80
应用配置:
> kubectl apply -f deployment.yaml
11.3 CI/CD集成
GitHub Actions示例:
name: Docker Image CIon:push:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4with:fetch-depth: 0 # 获取所有历史记录,便于生成标签- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Login to DockerHubuses: docker/login-action@v2with:username: ${{ secrets.DOCKERHUB_USERNAME }}password: ${{ secrets.DOCKERHUB_TOKEN }}- name: Extract metadata for Dockerid: metauses: docker/metadata-action@v5with:images: user/apptags: |type=shatype=ref,event=branchtype=ref,event=prtype=semver,pattern={{version}}type=semver,pattern={{major}}.{{minor}}- name: Build and pushuses: docker/build-push-action@v5with:context: .push: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }}cache-from: type=ghacache-to: type=gha,mode=max
💡 小贴士:Docker 23.0+引入了Buildx Build Cache,可以显著加速CI/CD中的镜像构建过程。使用GitHub Actions的缓存功能可以进一步提升构建效率。
11.4 Docker Swarm和Kubernetes对比
特性 | Docker Swarm | Kubernetes |
---|---|---|
学习曲线 | 简单,易于上手 | 陡峭,需要更多学习 |
安装配置 | 简单,Docker内置 | 复杂,需要单独安装 |
功能丰富度 | 基础功能 | 非常丰富,功能全面 |
社区支持 | 中等 | 非常活跃 |
适用场景 | 中小型应用,简单部署 | 大型应用,复杂部署 |
扩展性 | 有限 | 非常强大 |
自动伸缩 | 基础支持 | 高级支持 |
滚动更新 | 支持 | 高级支持 |
健康检查 | 基础支持 | 高级支持 |
网络策略 | 基础支持 | 高级支持 |
选择建议:
- 如果是小型团队或简单应用,Docker Swarm足够使用
- 如果需要高级功能或大规模部署,Kubernetes是更好的选择
- 对于本地开发,Docker Desktop内置的Kubernetes支持是理想选择
📝 本章练习
- 初始化一个Docker Swarm集群
- 部署一个简单的服务
- 扩展服务的副本数
- (挑战)尝试将你的应用部署到Kubernetes集群
附录A:Docker命令速查表
基础命令
命令 | 描述 |
---|---|
docker ps | 列出正在运行的容器 |
docker ps -a | 列出所有容器 |
docker images | 列出本地镜像 |
docker run [OPTIONS] IMAGE [COMMAND] | 运行容器 |
docker stop CONTAINER | 停止容器 |
docker start CONTAINER | 启动容器 |
docker rm CONTAINER | 删除容器 |
docker rmi IMAGE | 删除镜像 |
docker logs CONTAINER | 查看容器日志 |
docker exec -it CONTAINER COMMAND | 在运行的容器中执行命令 |
高级命令
命令 | 描述 |
---|---|
docker build -t TAG . | 构建镜像 |
docker-compose up | 启动Compose服务 |
docker network ls | 列出网络 |
docker volume ls | 列出数据卷 |
docker system df | 查看Docker磁盘使用 |
docker system prune | 清理未使用的资源 |
docker inspect CONTAINER | 查看容器详细信息 |
docker stats | 实时资源使用情况 |
docker events | 监听Docker事件 |
docker diff CONTAINER | 查看容器文件系统变化 |
附录B:推荐学习资源
📚 官方文档:
- Docker官方文档
- Docker Hub
- Compose Specification
📺 视频教程:
- Docker入门教程(B站)
- Docker & Kubernetes: The Practical Guide (Udemy)
💻 实践平台:
- Play with Docker
- Katacoda Docker场景
📖 书籍推荐:
- 《Docker技术入门与实战》
- 《Kubernetes权威指南》
🔧 实用工具:
- Trivy - 容器漏洞扫描工具
- Dive - 镜像层分析工具
- Lens - Kubernetes IDE
- Portainer - Docker管理UI
结语:继续你的Docker之旅
恭喜你完成了Docker入门学习!现在你已经掌握了Docker的核心概念和实用技能,可以开始在自己的项目中应用Docker了。
下一步建议:
- 实践项目:尝试将你现有的一个应用容器化
- 深入学习:
- 阅读Docker官方文档
- 学习Kubernetes基础知识
- 加入社区:
- Docker官方论坛
- Stack Overflow的docker标签
- 本地Docker/Kubernetes用户组
记住,最好的学习方式是动手实践!从简单开始,逐步增加复杂度,很快你就会成为Docker高手。
祝你在容器化旅程中一切顺利! 🐳
📝 附:学习进度检查表
✅ 已完成 | ❌ 未完成 | 📅 计划完成日期 |
---|---|---|
安装Docker | ||
运行第一个容器 | ||
理解Dockerfile | ||
使用Docker Compose | ||
配置Docker网络 | ||
实现数据持久化 | ||
部署完整Web应用 | ||
解决常见问题 | ||
应用最佳实践 | ||
探索进阶主题 |
填写你的学习计划,跟踪进度!