Files
docker_practice/network/port_mapping.md
2026-01-30 17:10:28 -08:00

150 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.

# 外部访问容器
## 为什么要映射端口
容器运行在自己的隔离网络环境中通常是 Bridge 模式这意味着
- **容器之间**可以通过 IP 或容器名自定义网络互通
- **宿主机访问容器**可以通过容器 IP 访问
- **外部网络访问容器** 默认无法直接访问
为了让外部如你的浏览器其他局域网机器访问容器内的服务我们需要将容器的端口**映射**到宿主机的端口
```
外部用户 (Browser)
宿主机 (localhost:8080)
┌────┴────┐ 端口映射
│ Docker │ (8080 -> 80)
│ Proxy │
└────┬────┘
容器 (Class B: 80)
```
---
## 端口映射方式
### 1. 指定映射 (-p)
使用 `-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)
使用 `-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 端口
---
## 查看端口映射
### docker port
```bash
$ docker port mycontainer
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080
```
### docker ps
```bash
$ docker ps
CONTAINER ID IMAGE PORTS NAMES
abc123456 nginx 0.0.0.0:8080->80/tcp web
```
---
## 最佳实践与安全
### 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 服务 DNS, Syslog
```bash
$ docker run -d -p 53:53/udp dns-server
```
---
## 实现原理
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 网络模式
---
## 本章小结
| 要点 | 说明 |
|------|------|
| **-p** | 指定端口映射常用 `8080:80` |
| **-P** | 随机映射所有 EXPOSE 的端口 |
| **安全性** | 默认监听所有 IP敏感服务应绑定 `127.0.0.1` |
| **查看** | 使用 `docker port` `docker ps` |
## 延伸阅读
- [EXPOSE 指令](../image/dockerfile/expose.md) Dockerfile 中声明端口
- [网络模式](README.md)Host 模式不需要端口映射