Fix naming of the chapter dir

This commit is contained in:
Baohua Yang
2026-02-22 12:42:15 -08:00
parent b9ac198f19
commit 92ea9623b2
130 changed files with 1001 additions and 852 deletions

41
09_network/README.md Normal file
View File

@@ -0,0 +1,41 @@
# 网络配置
Docker 容器需要网络来与外部世界通信容器之间相互通信以及与宿主机通信Docker 在安装时会自动配置网络基础设施大多数情况下开箱即用
## 概述
Docker 启动时自动创建以下网络组件
```mermaid
graph TD
subgraph Host [宿主机]
eth0[物理网卡 eth0<br>192.168.1.100]
docker0[docker0 网桥<br>172.17.0.1]
subgraph Containers
subgraph ContainerA [容器 A]
eth0_A[eth0<br>172.17.0.2]
end
subgraph ContainerB [容器 B]
eth0_B[eth0<br>172.17.0.3]
end
end
eth0 <--> docker0
docker0 <--> eth0_A
docker0 <--> eth0_B
end
Internet((互联网)) <--> eth0
```
本章将详细介绍 Docker 网络配置的各个方面
## 本章内容
* [配置 DNS](dns.md)
* [外部访问容器](port_mapping.md)
* [网络类型](network_types.md)
* [自定义网络](custom_network.md)
* [容器互联](container_linking.md)
* [网络隔离](network_isolation.md)

View File

@@ -0,0 +1,62 @@
## 9.5 容器互联
容器之间的网络通信是 Docker 网络的核心功能之一本节介绍容器互联的几种方式
### 9.5.1 同一网络内的容器
同一自定义网络内的容器可以直接通过容器名通信这是推荐的容器互联方式
```bash
## 创建网络
$ docker network create app-net
## 启动应用和数据库
$ docker run -d --name redis --network app-net redis
$ docker run -d --name app --network app-net myapp
## app 容器中可以用 redis:6379 连接 Redis
...
```
### 9.5.2 连接到多个网络
一个容器可以同时连接到多个网络这对于需要跨网络通信的中间件容器特别有用
```bash
## 启动容器
$ docker run -d --name multi-net-container --network frontend nginx
## 再连接到另一个网络
$ docker network connect backend multi-net-container
## 查看容器的网络
$ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}'
```
### 9.5.3 --link 已废弃
`--link` Docker 早期用于容器互联的方式**已经被废弃**不建议在新项目中使用请使用自定义网络替代
```bash
## 旧方式(不推荐)
$ docker run --link db:database myapp
## 新方式(推荐)
$ docker network create mynet
$ docker run --network mynet --name db postgres
$ docker run --network mynet --name app myapp
```
使用自定义网络的优势在于
- 原生支持 DNS 解析
- 不需要在容器启动时显式声明依赖
- 更灵活可以动态 connect/disconnect

View File

@@ -0,0 +1,93 @@
## 9.4 用户自定义网络 (推荐)
在生产环境中推荐使用用户自定义网络代替默认的 bridge 网络自定义网络提供了更好的隔离性和服务发现能力
### 9.4.1 为什么要用自定义网络
默认 bridge 网络存在以下局限而自定义网络可以很好地解决这些问题
| 问题 | 自定义网络的优势 |
|------|-----------------|
| 只能用 IP 通信 | 支持容器名 DNS 解析 |
| 所有容器在同一网络 | 更好的隔离性 |
| 需要 --link (已废弃)| 原生支持服务发现 |
### 9.4.2 创建自定义网络
使用 `docker network create` 命令可以创建自定义网络
```bash
## 创建网络
$ docker network create mynet
## 查看网络详情
$ docker network inspect mynet
```
### 9.4.3 使用自定义网络
启动容器时通过 `--network` 参数指定连接的网络
```bash
## 启动容器并连接到自定义网络
$ docker run -d --name web --network mynet nginx
$ docker run -d --name db --network mynet postgres
## 在 web 容器中可以直接用容器名访问 db
$ docker exec web ping db
PING db (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.083 ms
```
### 9.4.4 容器名 DNS 解析
自定义网络自动提供 DNS 服务Docker 守护进程在 `127.0.0.11` 运行了一个嵌入式 DNS 服务器容器内的 DNS 请求会被转发到这里
- 如果是容器名解析为容器 IP
- 如果是外部域名 ( google.com)转发给上游 DNS
```mermaid
flowchart LR
subgraph MyNet ["mynet 网络 : web 容器可以用 'db' 作为主机名访问 db 容器"]
direction LR
Web["web<br/>172.18.0.2"] -- "DNS: 'db' → 172.18.0.3" --> DB["db<br/>172.18.0.3"]
end
```
### 9.4.5 常用网络命令
以下是 Docker 网络管理中常用的命令
```bash
## 列出网络
$ docker network ls
## 创建网络
$ docker network create mynet
## 查看网络详情
$ docker network inspect mynet
## 连接容器到网络
$ docker network connect mynet mycontainer
## 断开网络连接
$ docker network disconnect mynet mycontainer
## 删除网络
$ docker network rm mynet
## 清理未使用的网络
$ docker network prune
```

106
09_network/dns.md Normal file
View File

@@ -0,0 +1,106 @@
## 9.2 配置 DNS
Docker 容器的 DNS 配置决定了容器如何解析域名理解 DNS 机制对于容器网络的正确配置至关重要
### 9.2.1 容器的 DNS 机制
Docker 容器的 DNS 配置有两种情况
1. **默认 Bridge 网络**继承宿主机的 DNS 配置 (`/etc/resolv.conf`)
2. **自定义网络** (推荐)使用 Docker 嵌入式 DNS 服务器 (Embedded DNS)支持通过 **容器名** 进行服务发现
---
### 9.2.2 嵌入式 DNS
这是 Docker 网络最强大的功能之一在自定义网络中容器可以通过 "名字" 找到彼此而不需要知道对方的 IP (因为 IP 可能会变)
```bash
## 1. 创建自定义网络
$ docker network create mynet
## 2. 启动容器 web 并加入网络
$ docker run -d --name web --network mynet nginx
## 3. 启动容器 client 并尝试 ping web
$ docker run -it --rm --network mynet alpine ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
```
**原理**
Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器容器内的 DNS 请求会被转发到这里如果是容器名解析为容器 IP如果是外部域名 ( google.com)转发给上游 DNS
---
### 9.2.3 配置 DNS 参数
如果你需要手动配置容器的 DNS (例如使用内网 DNS 服务器)可以在 `docker run` 中使用以下参数
#### 1. --dns
指定 DNS 服务器 IP
```bash
$ docker run -it --dns=114.114.114.114 ubuntu cat /etc/resolv.conf
nameserver 114.114.114.114
```
#### 2. --dns-search
指定 DNS 搜索域例如设置为 `example.com` `ping host` 会尝试解析 `host.example.com`
```bash
$ docker run --dns-search=example.com myapp
```
#### 3. --hostname (-h)
设置容器的主机名
```bash
$ docker run -h myweb nginx
```
---
### 9.2.4 全局 DNS 配置
如果希望所有容器都使用特定的 DNS 服务器 (而不是继承宿主机)可以修改 `/etc/docker/daemon.json`
```json
{
"dns": [
"114.114.114.114",
"8.8.8.8"
]
}
```
修改后需要重启 Docker 服务`systemctl restart docker`
---
### 9.2.5 常见问题
以下是使用容器 DNS 时常见的问题及解决方法
#### Q容器无法解析域名
**现象**`ping www.baidu.com` 失败 `ping 8.8.8.8` 成功**解决**
1. 宿主机的 `/etc/resolv.conf` 可能有问题 (例如使用了本地回环地址 127.0.0.53特别是 Ubuntu 系统)Docker 可能会尝试修复但有时会失败
2. 尝试手动指定 DNS`docker run --dns 8.8.8.8 ...`
3. 检查防火墙是否拦截了 UDP 53 端口
#### Q无法通过容器名通信
**现象**`ping db` 提示 `bad address 'db'`**原因**
- 你可能在使用 **默认的 bridge 网络**默认 bridge 网络 **不支持** 通过容器名进行 DNS 解析 (这是一个历史遗留设计)
- **解决**使用自定义网络 (`docker network create ...`)
---

View File

@@ -0,0 +1,81 @@
## 9.7 网络隔离
Docker 网络提供了天然的隔离能力不同网络之间的容器默认无法通信这是 Docker 网络安全的重要基础
### 9.7.1 网络隔离原理
不同网络之间默认隔离容器只能与同一网络中的容器直接通信
```bash
## 创建两个网络
$ docker network create frontend
$ docker network create backend
## 容器 A 在 frontend
$ docker run -d --name web --network frontend nginx
## 容器 B 在 backend
$ docker run -d --name db --network backend postgres
## web 无法直接访问 db不同网络
$ docker exec web ping db
ping: db: Name or service not known
```
### 9.7.2 安全优势
这种隔离机制带来以下安全优势
| 场景 | 说明 |
|------|------|
| **前后端分离** | 前端容器无法直接访问数据库网络 |
| **微服务隔离** | 不同微服务组可以使用不同网络 |
| **多租户** | 不同租户的容器在不同网络中完全隔离 |
| **最小权限** | 容器只能访问必要的网络资源 |
### 9.7.3 跨网络通信
如果确实需要某个容器跨网络通信可以将其同时连接到多个网络
```bash
## 创建一个中间件容器,连接到两个网络
$ docker run -d --name api --network frontend myapi
$ docker network connect backend api
## 现在 api 容器既可以访问 frontend 中的 web也可以访问 backend 中的 db
```
这种方式让你可以精确控制哪些容器可以跨网络通信遵循最小权限原则
### 9.7.4 典型网络架构
一个典型的多层应用网络架构如下
```mermaid
graph TD
subgraph FrontendNet ["frontend 网络"]
LB["负载均衡器"]
Web1["Web 服务器 1"]
Web2["Web 服务器 2"]
end
subgraph BackendNet ["backend 网络"]
API["API 服务器"]
DB["数据库"]
Cache["Redis 缓存"]
end
LB --> Web1
LB --> Web2
Web1 -.-> API
Web2 -.-> API
API --> DB
API --> Cache
```
在这种架构中API 服务器同时连接到 `frontend` `backend` 网络充当两个网络之间的桥梁负载均衡器和 Web 服务器无法直接访问数据库增强了安全性

View File

@@ -0,0 +1,78 @@
## 9.3 Docker 网络类型
Docker 提供了多种网络驱动来满足不同的使用场景安装 Docker 系统会自动创建三个默认网络
```bash
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
abc123... bridge bridge local
def456... host host local
ghi789... none null local
```
### 9.3.1 网络类型对比
各网络类型的特点和适用场景如下
| 网络类型 | 说明 | 适用场景 |
|---------|------|---------|
| **bridge** | 默认类型容器连接到虚拟网桥 | 大多数单机场景 |
| **host** | 容器直接使用宿主机网络栈 | 需要最高网络性能时 |
| **none** | 禁用网络 | 完全隔离的容器 |
| **overlay** | 跨主机网络 | Docker Swarm 集群 |
| **macvlan** | 容器拥有独立 MAC 地址 | 需要直接接入物理网络 |
### 9.3.2 Bridge 网络 (默认)
Bridge Docker 默认使用的网络模式Docker 启动时会自动创建 `docker0` 虚拟网桥所有未指定网络的容器都会连接到这个网桥上
核心组件如下
| 组件 | 说明 |
|------|------|
| **docker0** | 虚拟网桥充当交换机角色 |
| **veth pair** | 虚拟网卡对一端在容器内一端连接网桥 |
| **容器 eth0** | 容器内的网卡 |
| **IP 地址** | 自动从 172.17.0.0/16 网段分配 |
### 9.3.3 Host 网络
使用 `--network host` 参数启动的容器会直接使用宿主机的网络栈不再拥有独立的网络命名空间容器内的端口就是宿主机的端口无需端口映射
```bash
$ docker run -d --network host nginx
```
这种模式下网络性能最高但容器之间和宿主机之间没有网络隔离
### 9.3.4 None 网络
使用 `--network none` 参数启动的容器只有 `lo` 回环网卡完全没有外部网络连接适用于只需要运行计算任务不需要网络的容器
```bash
$ docker run -it --network none alpine ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> ...
inet 127.0.0.1/8 scope host lo
```
### 9.3.5 数据流向
容器网络中的数据流向可以分为以下几种情况
```mermaid
flowchart LR
subgraph Comm1 ["容器间通信"]
direction LR
C1A["容器 A (172.17.0.2)"] --> D0A["docker0"] --> C1B["容器 B (172.17.0.3)"]
end
subgraph Comm2 ["访问外网"]
direction LR
C2A["容器 A (172.17.0.2)"] --> D0B["docker0"] --> Eth0A["eth0"] --> InternetA["互联网"]
end
subgraph Comm3 ["被外部访问,需端口映射"]
direction LR
Req["外部请求"] --> Eth0B["eth0"] --> D0C["docker0"] --> C3A["容器 A"]
end
```

144
09_network/port_mapping.md Normal file
View File

@@ -0,0 +1,144 @@
## 9.6 外部访问容器
容器运行在自己的隔离网络环境中 (通常是 Bridge 模式)为了让外部网络访问容器内的服务我们需要将容器的端口映射到宿主机的端口
### 9.6.1 为什么要映射端口
容器的网络访问规则如下
- **容器之间**可以通过 IP 或容器名 (自定义网络) 互通
- **宿主机访问容器**可以通过容器 IP 访问
- **外部网络访问容器** 默认无法直接访问
为了让外部 (如你的浏览器其他局域网机器) 访问容器内的服务我们需要将容器的端口 **映射** 到宿主机的端口
```mermaid
flowchart TD
User["外部用户 (Browser)"] --> Host["宿主机 (localhost:8080)"]
Host --> Proxy["Docker Proxy<br/>端口映射 (8080 -> 80)"]
Proxy --> Container["容器 (Class B: 80)"]
```
---
### 9.6.2 端口映射方式
Docker 提供了多种方式来指定端口映射
#### 1. 指定映射
使用 `-p <宿主机端口>:<容器端口>` 格式
```bash
## 将宿主机的 8080 端口映射到容器的 80 端口
$ docker run -d -p 8080:80 nginx
```
此时访问 `http://localhost:8080` 即可看到 Nginx 页面
**多种格式**
| 格式 | 含义 | 示例 |
|------|------|------|
| `ip:hostPort:containerPort` | 绑定指定 IP 的特定端口 | `-p 127.0.0.1:8080:80` (仅本机访问) |
| `ip::containerPort` | 绑定指定 IP 的随机端口 | `-p 127.0.0.1::80` |
| `hostPort:containerPort` | 绑定所有 IP (0.0.0.0) 的特定端口 | `-p 8080:80` (默认) |
| `containerPort` | 绑定所有 IP 的随机端口 | `-p 80` |
#### 2. 随机映射
如果不关心宿主机使用哪个端口可以使用随机映射使用 `-P` (大写) 参数Docker 会随机映射 Dockerfile `EXPOSE` 指令暴露的所有端口到宿主机的高端口 (49000-49900)
```bash
$ docker run -d -P nginx
```
查看映射结果
```bash
$ docker ps
CONTAINER ID PORTS
abc123456 0.0.0.0:49153->80/tcp
```
此时 Nginx 被映射到了宿主机的 49153 端口
---
### 9.6.3 查看端口映射
可以使用以下命令查看容器的端口映射
#### docker port
运行 `docker port` 可以查看到指定容器的端口映射情况
```bash
$ docker port mycontainer
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080
```
#### docker ps
运行 `docker ps` 可以查看到所有容器的端口映射列表
```bash
$ docker ps
CONTAINER ID IMAGE PORTS NAMES
abc123456 nginx 0.0.0.0:8080->80/tcp web
```
---
### 9.6.4 最佳实践与安全
在配置端口映射时需要注意以下安全事项
#### 1. 限制监听 IP
默认情况下`-p 8080:80` 会监听 `0.0.0.0:8080`这意味着任何人只要能连接你的宿主机 IP就能访问该服务
如果不希望对外暴露 (例如数据库服务)应绑定到 `127.0.0.1`
```bash
## 仅允许本机访问
$ docker run -d -p 127.0.0.1:3306:3306 mysql
```
#### 2. 避免端口冲突
如果宿主机 8080 已经被占用了容器将无法启动
**解决**
- 更换宿主机端口`-p 8081:80`
- Docker 自动分配`-p 80`
#### 3. UDP 映射
默认是 TCP 协议如果要映射 UDP 服务 ( DNSSyslog)
```bash
$ docker run -d -p 53:53/udp dns-server
```
---
### 9.6.5 实现原理
Docker 使用 `docker-proxy` 进程 (用户态) `iptables` DNAT 规则 (内核态) 来实现端口转发
当流量到达宿主机端口时iptables 规则将其目标地址修改为容器 IP 并转发
```bash
## 简化的 iptables 逻辑
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
```
这也是为什么你在容器内部看到的访问来源 IP 通常是网关 IP ( 172.17.0.1)而不是真实的外部 Client IP (除非使用 host 网络模式)
---

24
09_network/summary.md Normal file
View File

@@ -0,0 +1,24 @@
## 9.8 本章小结
本章介绍了 Docker 网络配置的各个方面
| 概念 | 要点 |
|------|------|
| **DNS 配置** | 自定义网络支持嵌入式 DNS可通过容器名解析 |
| **网络类型** | bridge (默认)hostnoneoverlaymacvlan |
| **自定义网络** | 推荐使用支持容器名 DNS 解析和更好的隔离 |
| **容器互联** | 同一自定义网络内容器可直接通过容器名通信 |
| **端口映射** | `-p 宿主机端口:容器端口` 暴露服务到外部 |
| **网络隔离** | 不同网络默认隔离增强安全性 |
| **--link** | 已废弃使用自定义网络替代 |
### 9.8.1 延伸阅读
- [配置 DNS](dns.md)自定义 DNS 设置
- [网络类型](network_types.md)BridgeHostNone 等网络模式
- [自定义网络](custom_network.md)创建和管理自定义网络
- [容器互联](container_linking.md)容器间通信方式
- [端口映射](port_mapping.md)高级端口配置
- [网络隔离](network_isolation.md)网络安全与隔离策略
- [EXPOSE 指令](../07_dockerfile/7.9_expose.md) Dockerfile 中声明端口
- [Compose 网络](../11_compose/10.5_compose_file.md)Compose 中的网络配置