mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 04:14:38 +00:00
Release v1.5.0: Restructure chapters and update for Docker v30.x
This commit is contained in:
23
01_introduction/README.md
Normal file
23
01_introduction/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 简介
|
||||
|
||||
本章将带领你进入 **Docker** 的世界。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [什么是 Docker](what.md)
|
||||
* 介绍 Docker 的起源、发展历程以及其背后的核心技术(Cgroups, Namespaces, UnionFS)。
|
||||
* 了解 Docker 是如何改变软件交付方式的。
|
||||
|
||||
* [为什么要用 Docker](why.md)
|
||||
* 对比传统虚拟机技术,阐述 Docker 在启动速度、资源利用率、交付效率等方面的巨大优势。
|
||||
* 探讨 Docker 在 DevOps、微服务架构中的关键作用。
|
||||
|
||||
## 学习目标
|
||||
|
||||
通过本章的学习,你将能够:
|
||||
|
||||
1. 理解 Docker 的核心概念与架构。
|
||||
2. 明白 Docker 解决了现代软件开发与运维中的哪些痛点。
|
||||
3. 建立起对容器技术的初步认知,为后续的实战操作打下基础。
|
||||
|
||||
好吧,让我们带着问题开始这神奇之旅。
|
||||
65
01_introduction/quickstart.md
Normal file
65
01_introduction/quickstart.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# 快速上手 (5分钟)
|
||||
|
||||
本节将通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。
|
||||
|
||||
## 1. 准备代码
|
||||
|
||||
创建一个名为 `hello-docker` 的文件夹,并在其中创建一个 `index.html` 文件:
|
||||
|
||||
```html
|
||||
<h1>Hello, Docker!</h1>
|
||||
```
|
||||
|
||||
## 2. 编写 Dockerfile
|
||||
|
||||
在同级目录下创建一个名为 `Dockerfile` (无后缀) 的文件:
|
||||
|
||||
```dockerfile
|
||||
FROM nginx:alpine
|
||||
COPY index.html /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
## 3. 构建镜像
|
||||
|
||||
打开终端,进入该目录,执行构建命令:
|
||||
|
||||
```bash
|
||||
$ docker build -t my-hello-world .
|
||||
```
|
||||
|
||||
* `docker build`: 构建命令
|
||||
* `-t my-hello-world`: 给镜像起个名字(标签)
|
||||
* `.`: 指定上下文路径为当前目录
|
||||
|
||||
## 4. 运行容器
|
||||
|
||||
使用刚才构建的镜像启动一个容器:
|
||||
|
||||
```bash
|
||||
$ docker run -d -p 8080:80 my-hello-world
|
||||
```
|
||||
|
||||
* `docker run`: 运行命令
|
||||
* `-d`: 后台运行
|
||||
* `-p 8080:80`: 将宿主机的 8080 端口映射到容器的 80 端口
|
||||
|
||||
## 5. 访问测试
|
||||
|
||||
打开浏览器访问 [http://localhost:8080](http://localhost:8080),你应该能看到 "Hello, Docker!"。
|
||||
|
||||
## 6. 清理
|
||||
|
||||
停止并删除容器:
|
||||
|
||||
```bash
|
||||
# 查看正在运行的容器 ID
|
||||
$ docker ps
|
||||
|
||||
# 停止容器
|
||||
$ docker stop <CONTAINER_ID>
|
||||
|
||||
# 删除容器
|
||||
$ docker rm <CONTAINER_ID>
|
||||
```
|
||||
|
||||
恭喜!你已经完成了第一次 Docker 实战。接下来请阅读 [Docker 核心概念](../02_basic_concept/README.md) 做深入了解。
|
||||
124
01_introduction/what.md
Normal file
124
01_introduction/what.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# 什么是 Docker
|
||||
|
||||
## 一句话理解 Docker
|
||||
|
||||
> **Docker 是一种轻量级的虚拟化技术,它让应用程序及其依赖环境可以被打包成一个标准化的单元,在任何地方都能一致地运行。**
|
||||
|
||||
如果用一个生活中的类比:**Docker 之于软件,就像集装箱之于货物**。
|
||||
|
||||
在集装箱发明之前,货物的运输是一件麻烦的事情——不同的货物需要不同的包装、不同的装卸方式,换一种运输工具就要重新装卸。集装箱的出现改变了这一切:无论里面装的是什么,集装箱的外形是标准的,可以用同样的方式装卸、堆放和运输。
|
||||
|
||||
Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还是其他语言写的,无论它需要什么样的依赖库和环境,一旦被打包成 Docker 镜像,就可以用同样的方式在任何支持 Docker 的机器上运行。
|
||||
|
||||
## Docker 的核心价值
|
||||
|
||||
笔者认为,Docker 解决的是软件开发中最古老的问题之一:**"在我机器上明明能跑啊!"**
|
||||
|
||||
```
|
||||
开发环境 生产环境
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Python 3.14 │ ≠ │ Python 3.11 │
|
||||
│ Ubuntu 24.04 │ │ Ubuntu 22.04 │
|
||||
│ 特定版本的库 │ │ 不同版本的库 │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
↓ ↓
|
||||
运行正常 运行失败!
|
||||
```
|
||||
|
||||
有了 Docker:
|
||||
|
||||
```
|
||||
开发环境 生产环境
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Docker 镜像 │ = │ 同一个镜像 │
|
||||
│ (包含所有依赖) │ │ (完全一致) │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
↓ ↓
|
||||
运行正常 运行正常!
|
||||
```
|
||||
|
||||
## Docker vs 虚拟机
|
||||
|
||||
很多人第一次接触 Docker 时会问:**"这不就是虚拟机吗?"**
|
||||
|
||||
答案是:**不是,而且差别很大。**
|
||||
|
||||
### 传统虚拟机
|
||||
|
||||
传统虚拟机技术是虚拟出一套完整的硬件,在其上运行一个完整的操作系统,再在该系统上运行应用:
|
||||
|
||||

|
||||
|
||||
### Docker 容器
|
||||
|
||||
而 Docker 容器内的应用直接运行于宿主的内核,容器内没有自己的内核,也没有进行硬件虚拟:
|
||||
|
||||

|
||||
|
||||
### 关键区别
|
||||
|
||||
| 特性 | Docker 容器 | 传统虚拟机 |
|
||||
|------|-------------|------------|
|
||||
| **启动速度** | 秒级 | 分钟级 |
|
||||
| **资源占用** | MB 级别 | GB 级别 |
|
||||
| **性能** | 接近原生 | 有明显损耗 |
|
||||
| **隔离级别** | 进程级隔离 | 完全隔离 |
|
||||
| **单机数量** | 可运行上千个 | 通常几十个 |
|
||||
|
||||
> 笔者经常用这个类比来解释:虚拟机像是每个应用都住在一栋独立的房子里(有自己的地基、水电系统),而容器像是大家住在同一栋公寓楼里的不同房间(共享地基和水电系统,但各自独立)。
|
||||
|
||||
## Docker 的技术基础
|
||||
|
||||
Docker 使用 [Go 语言](https://golang.google.cn/) 开发,基于 Linux 内核的以下技术:
|
||||
|
||||
- **[Namespace](https://en.wikipedia.org/wiki/Linux_namespaces)**:实现资源隔离(进程、网络、文件系统等)
|
||||
- **[Cgroups](https://zh.wikipedia.org/wiki/Cgroups)**:实现资源限制(CPU、内存、I/O 等)
|
||||
- **[Union FS](https://en.wikipedia.org/wiki/Union_mount)**:实现分层存储(如 OverlayFS)
|
||||
|
||||
> 如果你对这些底层技术感兴趣,可以阅读本书的[底层实现](../13_implementation/README.md)章节。
|
||||
|
||||
### Docker 架构演进
|
||||
|
||||
Docker 的底层实现经历了多次演进:
|
||||
|
||||
```
|
||||
2013 2014 2015 现在
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
LXC ──→ libcontainer ──→ runC ──→ containerd + runC
|
||||
│
|
||||
└── OCI 标准化
|
||||
```
|
||||
|
||||
- **LXC**(2013):Docker 最初基于 Linux Containers
|
||||
- **libcontainer**(2014,v0.7):Docker 自研的容器运行时
|
||||
- **runC**(2015,v1.11):捐献给 OCI 的标准容器运行时
|
||||
- **containerd**:高级容器运行时,管理容器生命周期
|
||||
|
||||

|
||||
|
||||
> `runc` 是一个 Linux 命令行工具,用于根据 [OCI 容器运行时规范](https://github.com/opencontainers/runtime-spec) 创建和运行容器。
|
||||
|
||||
> `containerd` 是一个守护程序,它管理容器生命周期,提供了在一个节点上执行容器和管理镜像的最小功能集。
|
||||
|
||||
## Docker 的历史与生态
|
||||
|
||||
**Docker** 最初是 `dotCloud` 公司创始人 [Solomon Hykes](https://github.com/shykes) 在法国期间发起的一个公司内部项目,于 [2013 年 3 月以 Apache 2.0 授权协议开源](https://en.wikipedia.org/wiki/Docker_(software))。
|
||||
|
||||
Docker 的发展历程:
|
||||
|
||||
- **2013 年 3 月**:开源发布
|
||||
- **2013 年底**:dotCloud 公司改名为 Docker, Inc.
|
||||
- **2015 年**:成立 [开放容器联盟(OCI)](https://opencontainers.org/),推动容器标准化
|
||||
- **至今**:[GitHub 项目](https://github.com/moby/moby) 超过 7 万星标
|
||||
|
||||
Docker 的成功推动了整个容器生态的发展,催生了 Kubernetes、Podman 等众多相关项目。笔者认为,Docker 最大的贡献不仅是技术本身,更是它**让容器技术从系统管理员的工具变成了每个开发者都能使用的标准工具**。
|
||||
|
||||
## 本章小结
|
||||
|
||||
- Docker 是一种轻量级虚拟化技术,核心价值是**环境一致性**
|
||||
- 与虚拟机相比,Docker 更轻量、更快速、资源利用率更高
|
||||
- Docker 基于 Linux 内核的 Namespace、Cgroups 和 Union FS 技术
|
||||
- Docker 推动了容器技术的标准化(OCI)和生态发展
|
||||
|
||||
接下来,让我们了解[为什么要使用 Docker](why.md)。
|
||||
208
01_introduction/why.md
Normal file
208
01_introduction/why.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# 为什么要使用 Docker?
|
||||
|
||||
在回答"为什么用 Docker"之前,笔者想先问一个问题:**你有没有经历过这些场景?**
|
||||
|
||||
## 没有 Docker 的世界
|
||||
|
||||
### 场景一:"在我电脑上明明能跑"
|
||||
|
||||
```
|
||||
周五下午 5:00
|
||||
├── 开发者:代码写完了,本地测试通过,提交!🎉
|
||||
├── 周一早上 9:00
|
||||
│ └── 测试:"这个功能在测试环境跑不起来"
|
||||
└── 开发者:" 不可能,在我电脑上明明能跑啊……"
|
||||
```
|
||||
|
||||
笔者统计过,这个问题通常由以下原因导致:
|
||||
- Python/Node/Java 版本不一致
|
||||
- 依赖库版本不一致
|
||||
- 操作系统配置不一致
|
||||
- 某些环境变量没有设置
|
||||
- "哦,忘了说我本地装了个 XXX"
|
||||
|
||||
### 场景二:环境配置的噩梦
|
||||
|
||||
```
|
||||
新同事入职
|
||||
├── Day 1:领电脑,配环境
|
||||
├── Day 2:继续配环境,遇到问题
|
||||
├── Day 3:换种方法配环境
|
||||
├── Day 4:问老同事怎么配的,他也忘了
|
||||
└── Day 5:终于能跑起来了!但不知道为什么……
|
||||
```
|
||||
|
||||
### 场景三:服务器迁移的恐惧
|
||||
|
||||
```
|
||||
运维:"我们需要把服务迁移到新服务器"
|
||||
开发:"旧服务器上的配置文档在哪?"
|
||||
运维:"当时是一个已经离职的同事配的……"
|
||||
所有人:😱
|
||||
```
|
||||
|
||||
## Docker 如何解决这些问题
|
||||
|
||||
### 核心理念:一次构建,到处运行
|
||||
|
||||
```
|
||||
开发环境 测试环境 生产环境
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│ Docker │ = │ Docker │ = │ Docker │
|
||||
│ 镜像 │ │ 镜像 │ │ 镜像 │
|
||||
└─────────┘ └─────────┘ └─────────┘
|
||||
↓ ↓ ↓
|
||||
完全一致 完全一致 完全一致
|
||||
```
|
||||
|
||||
## Docker 的核心优势
|
||||
|
||||
### 1. 环境一致性
|
||||
|
||||
Docker 镜像包含了应用运行所需的**一切**:代码、运行时、系统工具、库、配置。这意味着:
|
||||
|
||||
- ✅ 开发环境和生产环境完全一致
|
||||
- ✅ 不会再有"在我机器上能跑"的问题
|
||||
- ✅ 新人入职,一条命令就能启动开发环境
|
||||
|
||||
```bash
|
||||
# 新同事入职第一天
|
||||
$ git clone https://github.com/company/project.git
|
||||
$ docker compose up
|
||||
# 完整的开发环境就准备好了
|
||||
```
|
||||
|
||||
### 2. 秒级启动
|
||||
|
||||
传统虚拟机启动需要几分钟(引导操作系统),而 Docker 容器启动通常只需要**几秒甚至几百毫秒**。
|
||||
|
||||
笔者实测数据:
|
||||
|
||||
| 启动内容 | 虚拟机 | Docker 容器 |
|
||||
|---------|--------|-------------|
|
||||
| 空系统 | ~60 秒 | ~0.5 秒 |
|
||||
| MySQL | ~90 秒 | ~3 秒 |
|
||||
| 完整 Web 应用 | ~120 秒 | ~5 秒 |
|
||||
|
||||
这个差异对以下场景尤为重要:
|
||||
- **CI/CD 流水线**:每次构建节省几分钟,一天累积下来就是几小时
|
||||
- **弹性扩容**:流量高峰时能快速启动更多实例
|
||||
- **开发体验**:快速重启服务进行调试
|
||||
|
||||
### 3. 资源效率
|
||||
|
||||
Docker 容器共享宿主机内核,无需为每个应用运行完整的操作系统。
|
||||
|
||||
```
|
||||
传统虚拟机方案:
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ 物理服务器 (64GB 内存) │
|
||||
├──────────────┬───────────────┬─────────────────┤
|
||||
│ VM1 │ VM2 │ VM3 │
|
||||
│ 8GB 内存 │ 8GB 内存 │ 8GB 内存 │
|
||||
│ (含 OS 2GB) │ (含 OS 2GB) │ (含 OS 2GB) │
|
||||
│ 应用 1 │ 应用 2 │ 应用 3 │
|
||||
└──────────────┴───────────────┴─────────────────┘
|
||||
实际可用于应用:3 × 6GB = 18GB ❌
|
||||
|
||||
Docker 方案:
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ 物理服务器 (64GB 内存) │
|
||||
│ 宿主机 OS + Docker (约 4GB) │
|
||||
├──────────────┬───────────────┬─────────────────┤
|
||||
│ 容器 1 │ 容器 2 │ 容器 3 │
|
||||
│ 应用 1 │ 应用 2 │ 应用 3 │
|
||||
│ (按需分配) │ (按需分配) │ (按需分配) │
|
||||
└──────────────┴───────────────┴─────────────────┘
|
||||
实际可用于应用:约 60GB ✅
|
||||
```
|
||||
|
||||
### 4. 持续交付和部署
|
||||
|
||||
Docker 完美契合 DevOps 的工作流程:
|
||||
|
||||
```
|
||||
代码提交 ──→ 自动构建镜像 ──→ 自动测试 ──→ 自动部署
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
Git docker 容器内 容器滚动
|
||||
push build 运行测试 更新
|
||||
```
|
||||
|
||||
使用 [Dockerfile](../04_image/build.md) 定义镜像构建过程,使得:
|
||||
- 构建过程**可重复、可追溯**
|
||||
- 任何人都能从代码重建完全相同的镜像
|
||||
- 配合 [GitHub Actions](../14_cases/ci/actions/README.md) 等 CI 系统实现自动化
|
||||
|
||||
### 5. 轻松迁移
|
||||
|
||||
Docker 可以在几乎任何平台上运行:
|
||||
- ✅ 本地开发机(macOS、Windows、Linux)
|
||||
- ✅ 公有云(AWS、Azure、GCP、阿里云、腾讯云)
|
||||
- ✅ 私有云和自建数据中心
|
||||
- ✅ 边缘设备和 IoT
|
||||
|
||||
**同一个镜像,在任何地方运行结果都一致。** 这让应用迁移变得前所未有的简单。
|
||||
|
||||
### 6. 微服务架构的基石
|
||||
|
||||
现代微服务架构几乎都依赖容器技术。Docker 让你可以:
|
||||
|
||||
- **隔离服务**:每个服务运行在独立容器中,互不干扰
|
||||
- **独立扩展**:哪个服务负载高,就单独扩展哪个
|
||||
- **独立部署**:更新一个服务不影响其他服务
|
||||
- **技术多样**:不同服务可以用不同语言和框架
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────┐
|
||||
│ 微服务架构示例 │
|
||||
├─────────────┬─────────────┬───────────────────────┤
|
||||
│ 前端容器 │ API 容器 │ Worker 容器 │
|
||||
│ (Node.js) │ (Python) │ (Go) │
|
||||
├─────────────┴─────────────┴───────────────────────┤
|
||||
│ Redis 容器 │
|
||||
├───────────────────────────────────────────────────┤
|
||||
│ PostgreSQL 容器 │
|
||||
└───────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Docker 不适合的场景
|
||||
|
||||
笔者认为,技术选型要客观。Docker 并非银弹,以下场景可能不太适合:
|
||||
|
||||
### 1. 需要完全隔离的场景
|
||||
|
||||
容器共享宿主机内核,隔离性不如虚拟机。如果你需要运行不受信任的代码,虚拟机可能更安全。
|
||||
|
||||
### 2. 需要特殊内核的场景
|
||||
|
||||
容器使用宿主机内核。如果应用需要特定版本的内核或内核模块,可能需要虚拟机。
|
||||
|
||||
### 3. Windows 原生应用
|
||||
|
||||
虽然 Docker 支持 Windows 容器,但生态不如 Linux 容器成熟。传统 Windows 应用的容器化仍有挑战。
|
||||
|
||||
### 4. 桌面应用
|
||||
|
||||
Docker 主要面向服务端应用。桌面 GUI 应用的容器化虽然可行,但通常得不偿失。
|
||||
|
||||
## 与传统虚拟机的对比总结
|
||||
|
||||
| 特性 | Docker 容器 | 传统虚拟机 |
|
||||
|:------|:-----------|:-----------|
|
||||
| 启动速度 | 秒级 | 分钟级 |
|
||||
| 磁盘占用 | MB 级别 | GB 级别 |
|
||||
| 性能 | 接近原生 | 有 5-20% 损耗 |
|
||||
| 单机支持量 | 上千个容器 | 几十个虚拟机 |
|
||||
| 隔离性 | 进程级别 | 完全隔离 |
|
||||
| 最佳场景 | 微服务、CI/CD、开发环境 | 多租户、高安全需求 |
|
||||
|
||||
## 本章小结
|
||||
|
||||
Docker 的核心价值可以用一句话概括:**让应用的开发、测试、部署保持一致,同时极大提高资源利用效率。**
|
||||
|
||||
笔者认为,对于现代软件开发者来说,Docker 已经不是"要不要学"的问题,而是**必备技能**。无论你是前端、后端、运维还是全栈开发者,掌握 Docker 都能让你的工作更高效。
|
||||
|
||||
接下来,让我们学习 Docker 的[基本概念](../02_basic_concept/README.md)。
|
||||
Reference in New Issue
Block a user