Docker 入门学习笔记 03:端口映射到底是什么,为什么容器启动了却访问不到
文章目录
- [Docker 入门学习笔记 03:端口映射到底是什么,为什么容器启动了却访问不到](#Docker 入门学习笔记 03:端口映射到底是什么,为什么容器启动了却访问不到)
-
- 一、先理解核心问题
- 二、为什么会有端口这个概念
- 三、容器里的端口和宿主机端口不是一回事
- 四、什么叫端口映射
- 五、一个最常见的例子
- [六、为什么学习时推荐用 `8080:80`](#六、为什么学习时推荐用
8080:80) - 七、端口映射成功后会看到什么
- [八、这段 `PORTS` 应该怎么理解](#八、这段
PORTS应该怎么理解) - 九、如何验证映射真的生效
- 十、最容易混淆的三个点
-
- [1. 容器启动成功,不代表宿主机能访问](#1. 容器启动成功,不代表宿主机能访问)
- [2. `-p 8080:80` 里的顺序不能写反](#2.
-p 8080:80里的顺序不能写反) - [3. 宿主机同一个端口不能随便重复占用](#3. 宿主机同一个端口不能随便重复占用)
- 十一、一个常见的名字冲突问题
- 十二、这一部分学完后应该掌握什么
- 十三、这一部分最值得记住的一句话
- 十四、下一步要学什么
本专栏文章导航
- 第 01 篇:Docker 入门学习笔记 01:它到底解决了什么问题,镜像和容器又是什么
- 第 02 篇:Docker 入门学习笔记 02:基础命令、前后台运行,以及 attach、logs、exec 的区别
- 第 03 篇:Docker 入门学习笔记 03:端口映射到底是什么,为什么容器启动了却访问不到
- 第 04 篇:Docker 入门学习笔记 04:环境变量到底在做什么,为什么很多容器都依赖它
- 第 05 篇:Docker 入门学习笔记 05:卷到底是什么,为什么容器删了数据却还能保留
- 第 06 篇:Docker 入门学习笔记 06:用一个可复现的 Python 项目真正理解 Dockerfile
- 第 07 篇:Docker 入门学习笔记 07:用一个多服务案例真正理解 Docker Compose
这一篇开始进入 Docker 学习里非常关键的一步:
为什么容器里的服务已经启动了,但宿主机还是访问不到?
这个问题看起来很基础,但它会直接影响后面学习:
Docker Compose- 容器网络
- 微服务部署
Kubernetes Service
所以端口映射这一步一定要真正理解,而不是只记住一个 -p 参数。
一、先理解核心问题
例如执行下面这条命令:
bash
docker run --name mynginx nginx
这时 Nginx 确实已经在容器里启动了,但这并不代表宿主机就能直接访问。
原因在于:
- 服务运行在容器内部
- 容器有自己的网络空间
- 容器内部监听的端口,不会自动暴露给宿主机
所以首先要记住一句话:
容器里的端口,不等于宿主机的端口。
二、为什么会有端口这个概念
理解端口映射之前,先要知道为什么网络里会有"端口"。
一台机器上可以同时运行很多网络服务,例如:
- Web 服务
- 数据库
- Redis
- SSH
- 监控系统
这些服务可能都在同一个 IP 上运行。
如果没有端口,系统就无法区分:
这次请求到底要交给哪个服务处理?
所以可以这样理解:
IP像一栋楼的地址端口像楼里的房间号
请求先到这栋楼,再根据端口号被送到不同服务。
例如常见端口:
80:HTTP443:HTTPS22:SSH3306:MySQL6379:Redis
三、容器里的端口和宿主机端口不是一回事
Docker 里最容易误解的一点就是:
容器里的 80 端口,不等于宿主机的 80 端口。
例如 Nginx 在容器里监听 80,它只是说明:
这个服务在容器内部的 80 端口上提供服务。
但宿主机并不会自动把自己的某个端口交给它使用。
如果希望宿主机也能访问到这个服务,就必须显式做端口映射。
四、什么叫端口映射
Docker 里最常见的写法是:
bash
-p 宿主机端口:容器端口
例如:
bash
-p 8080:80
它表示:
- 宿主机访问
8080 - Docker 把流量转发到容器内部的
80
所以更准确地说:
-p 8080:80 不是"开放两个端口",而是"把宿主机 8080 转发到容器 80"。`
五、一个最常见的例子
下面这条命令是学习端口映射时最经典的例子:
bash
docker run -d --name mynginx -p 8080:80 nginx
它可以拆成四部分理解:
-d:后台运行--name mynginx:给容器起名字-p 8080:80:宿主机8080映射到容器80nginx:使用 Nginx 镜像
它的真正含义是:
启动一个运行在容器里的 nginx,并把它的 80 端口暴露到宿主机的 8080 端口上。
六、为什么学习时推荐用 8080:80
理论上也可以写成:
bash
-p 80:80
但在学习阶段,更推荐先用:
bash
-p 8080:80
这样有两个好处:
- 不容易和宿主机已有服务冲突
- 更容易区分"宿主机端口"和"容器端口"是两个不同概念
学习时故意让两个数字不一样,理解会更清楚。
七、端口映射成功后会看到什么
执行下面这条命令:
bash
docker run -d --name mynginx -p 8080:80 nginx
如果启动成功,终端通常会返回一个容器 ID,例如:
text
a2b2ae9e288595d09281f23f8139c63fd67ee428e68ec474bc732aa901fe54ce
然后执行:
bash
docker ps
可以看到类似下面的输出:
text
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2b2ae9e2885 nginx "/docker-entrypoint...." 5 seconds ago Up 4 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp mynginx
这里最值得关注的是 PORTS 这一列:
text
0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
学习阶段可以先抓住最核心的部分:
宿主机 8080 -> 容器 80/tcp
八、这段 PORTS 应该怎么理解
以这段输出为例:
text
0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
可以先这样理解:
0.0.0.0:8080->80/tcp:宿主机所有 IPv4 地址上的8080,都转发到容器80/tcp[::]:8080->80/tcp:宿主机所有 IPv6 地址上的8080,也转发到容器80/tcp
如果刚开始觉得 IPv4、IPv6 太多,可以先记最核心的一句:
访问宿主机的 8080,就会被转发到容器里的 80。
九、如何验证映射真的生效
最简单的方法就是直接访问宿主机对应端口:
bash
curl http://localhost:8080
如果映射成功,通常会看到一段 HTML 内容,例如:
html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<h1>Welcome to nginx!</h1>
...
</html>
这说明两件事:
- 容器里的 Nginx 确实启动成功了
- 宿主机
8080已经成功转发到了容器80
十、最容易混淆的三个点
1. 容器启动成功,不代表宿主机能访问
容器启动成功,只说明容器里的进程活着。
是否能从宿主机访问,还取决于是否做了端口映射。
2. -p 8080:80 里的顺序不能写反
顺序必须是:
bash
宿主机:容器
也就是:
bash
-p 8080:80
不是反过来。
3. 宿主机同一个端口不能随便重复占用
如果已经有一个容器使用了宿主机 8080,再启动另一个容器也想绑定 8080,通常会冲突。
例如:
bash
docker run -d --name nginx2 -p 8080:80 nginx
这种情况下,宿主机的 8080 一般已经被前一个容器占用了。
所以更常见的做法是换一个宿主机端口,例如:
bash
docker run -d --name nginx2 -p 8081:80 nginx
这时就会变成:
localhost:8080-> 第一个容器localhost:8081-> 第二个容器
十一、一个常见的名字冲突问题
在练习过程中,还有一个很常见的问题不是端口冲突,而是容器名字冲突。
例如执行:
bash
docker run -d --name mynginx -p 8080:80 nginx
如果之前已经存在一个叫 mynginx 的容器,即使它已经退出,也仍然会报错。
常见错误类似这样:
text
docker: Error response from daemon: Conflict. The container name "/mynginx" is already in use ...
这时候说明:
- 问题不是端口本身
- 而是容器名字已经被占用
解决方法通常是先删除旧容器:
bash
docker rm mynginx
然后再重新启动。
这个问题也提醒了一个很重要的学习点:
容器退出了,不等于容器对象已经不存在。
十二、这一部分学完后应该掌握什么
如果这一部分真正掌握了,应该能清楚表达这些内容:
- 容器内部端口和宿主机端口不是同一个概念
-p 宿主机端口:容器端口表示端口映射-p 8080:80表示宿主机8080转发到容器80docker ps里的PORTS能帮助判断映射是否生效curl http://localhost:8080能验证服务是否真的通了- 宿主机同一个端口通常不能同时重复绑定给多个容器
十三、这一部分最值得记住的一句话
如果只记一句话,最值得记住的是:
服务跑在容器里,不等于宿主机就能访问;要访问它,必须先把宿主机端口映射到容器端口。
十四、下一步要学什么
端口映射讲清楚之后,下一步最自然的延伸就是:
- 为什么有些服务即使映射了端口也访问不到
- 环境变量是怎么传进容器的
- 数据为什么需要卷
也就是说,后面会继续进入"容器运行要素"的另外两块内容:
- 环境变量
- 卷
本专栏文章导航
- 第 01 篇:Docker 入门学习笔记 01:它到底解决了什么问题,镜像和容器又是什么
- 第 02 篇:Docker 入门学习笔记 02:基础命令、前后台运行,以及 attach、logs、exec 的区别
- 第 03 篇:Docker 入门学习笔记 03:端口映射到底是什么,为什么容器启动了却访问不到
- 第 04 篇:Docker 入门学习笔记 04:环境变量到底在做什么,为什么很多容器都依赖它
- 第 05 篇:Docker 入门学习笔记 05:卷到底是什么,为什么容器删了数据却还能保留
- 第 06 篇:Docker 入门学习笔记 06:用一个可复现的 Python 项目真正理解 Dockerfile
- 第 07 篇:Docker 入门学习笔记 07:用一个多服务案例真正理解 Docker Compose