文章目录
- 环境
- 总结
- 测试
- 使用EXPOSE
- 测试1:不做端口映射
- 测试2:-p 8080:80
- 测试3:-P
- 测试4:--network=host
 
- 不使用EXPOSE
 
- 参考
环境
- RHEL 9.3
- Docker Community 24.0.7
总结
如果懒得看测试的详细信息,可以直接看结果:
| docker run选项 | 在Dockerfile里 EXPOSE 80 | 在Dockerfile里不 EXPOSE 80 | 备注 | 
|---|---|---|---|
| 无 | 在容器外无法访问容器的80端口 | 在容器外无法访问容器的80端口 | |
| -p 8080:80 | 8080 | 8080 | 显式指定映射端口 | 
| -P | 随机端口 | 随机端口 | 随机映射端口 | 
| --network=host | 80 | 80 | 直接使用容器的端口 | 
所以,EXPOSE并不会真正开放端口,它更像是一个说明文档,由image的开发者声明image所监听的端口,使用者以此为依据,在启动容器时,可以以不同的策略来开放端口。
测试
使用EXPOSE
创建 Dockerfile 文件如下:
FROM nginx:alpineEXPOSE 80
构建:
docker build -t kai0107_1 .
测试1:不做端口映射
启动容器:
docker run kai0107_1
查看容器:
➜  ~ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS     NAMES
430b0c2bee65   kai0107_1   "/docker-entrypoint.…"   5 seconds ago   Up 5 seconds   80/tcp    recursing_noyce
检查该容器:
➜  ~ docker container inspect 430b0c2bee65 | grep -i3 port"Config": {}},"NetworkMode": "default","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0
--"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "",
--"AttachStdin": false,"AttachStdout": true,"AttachStderr": true,"ExposedPorts": {"80/tcp": {}},"Tty": false,
--"HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {"80/tcp": null},"SandboxKey": "/var/run/docker/netns/c762f4dc271b",
注:可以用 -f 选项指定输出格式,参见 https://docs.docker.com/engine/reference/commandline/inspect 。
打开浏览器,访问 http://localhost:80 ,如下:

可见,在容器之外,无法访问80端口。
测试2:-p 8080:80
启动容器:
docker run -p 8080:80 kai0107_1
查看容器:
➜  ~ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED              STATUS              PORTS                                   NAMES
dd9ea9e98b4b   kai0107_1   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp   naughty_almeida
注: 0.0.0.0 和 :: 都是代表匹配所有IP地址。前者是IPv4的写法,后者是IPv6的写法。
检查该容器:
➜  ~ docker container inspect dd9ea9e98b4b | grep -i3 port"Config": {}},"NetworkMode": "default","PortBindings": {"80/tcp": [{"HostIp": "","HostPort": "8080"}]},
--"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "",
--"AttachStdin": false,"AttachStdout": true,"AttachStderr": true,"ExposedPorts": {"80/tcp": {}},"Tty": false,
--"HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {"80/tcp": [{"HostIp": "0.0.0.0","HostPort": "8080"},{"HostIp": "::","HostPort": "8080"}]},
打开浏览器,访问 http://localhost:8080 ,如下:

可见,在容器外部,可以通过8080端口访问容器里的80端口。
测试3:-P
启动容器:
docker run -P kai0107_1
查看容器:
➜  ~ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                                     NAMES
241fd7f0ee87   kai0107_1   "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds   0.0.0.0:32768->80/tcp, :::32768->80/tcp   jovial_haslett
检查该容器:
➜  ~ docker container inspect 241fd7f0ee87 | grep -i3 port"Config": {}},"NetworkMode": "default","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0
--"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": true,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "",
--"AttachStdin": false,"AttachStdout": true,"AttachStderr": true,"ExposedPorts": {"80/tcp": {}},"Tty": false,
--"HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {"80/tcp": [{"HostIp": "0.0.0.0","HostPort": "32768"},{"HostIp": "::","HostPort": "32768"}]},
打开浏览器,访问 http://localhost:32768 ,如下:

可见,在容器外部,可以通过32768端口访问容器里的80端口。
注意:32768是一个随机端口。下次再启动容器时,可能就是另外一个端口了。
测试4:–network=host
启动容器:
docker run --network=host kai0107_1
查看容器:
➜  ~ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS     NAMES
adcbcdd4698c   kai0107_1   "/docker-entrypoint.…"   6 seconds ago   Up 6 seconds             quizzical_hugle
检查该容器:
➜  ~ docker container inspect adcbcdd4698c | grep -i3 port"Config": {}},"NetworkMode": "host","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0
--"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "",
--"AttachStdin": false,"AttachStdout": true,"AttachStderr": true,"ExposedPorts": {"80/tcp": {}},"Tty": false,
--"HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {},"SandboxKey": "/var/run/docker/netns/default","SecondaryIPAddresses": null,"SecondaryIPv6Addresses": null,
打开浏览器,访问 http://localhost:80 ,如下:

 可见,在容器外部,可以通过80端口访问容器里的80端口。
不使用EXPOSE
创建 Dockerfile 文件如下:
FROM nginx:alpine
再次做测试1到测试4,其结果和使用EXPOSE时是完全一致的。
参考
- https://docs.docker.com/engine/reference/run/#expose-incoming-ports
- https://blog.csdn.net/qq_33801641/article/details/121122334
- https://www.php.cn/faq/494255.html
- https://yeasy.gitbook.io/docker_practice/network/port_mapping