Files
docker_practice/09_network/port_mapping.md
2026-02-22 12:42:15 -08:00

145 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 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 网络模式)
---