今天來系統聊一聊docker的端口,常見的有容器內程序端口、容器端口、主機端口、Dockerfile中EXPOSE端口、docker-compose和docker run中的port等。
貌似很多端口,但連接時真實的端口僅程序端口和主機端口,其他都是對端口的聲明,並不會實際開啟端口的服務。
下面以nginx和redis鏡像為例介紹下這些端口的關系:nginx程序端口80,映射主機端口30080;redis程序端口6379,映射主機端口36379。實際通信如下圖
程序端口即容器端口
- 程序端口即實際容器端口,它們是同一個端口。不映射主機端口,容器啟動后,本機或同網絡其他容器通過容器內程序端口(即容器端口)訪問該容器的服務成功,外網訪問失敗。
以nginx為例,啟動容器(名稱web)
[root@localhost ~]# docker run -d --name web nginx 3cb58fd8e585e0b015e7e42e9587df95359e1d133ff5371c6838fd303132d2ef [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3cb58fd8e585 nginx "/docker-entrypoint.…" 17 seconds ago Up 15 seconds 80/tcp web
本地服務器驗證訪問容器,返回如下高亮信息表示端口訪問正常
[root@localhost ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
172.17.0.2
[root@localhost ~]# curl http://172.17.0.2:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1>
。。。。。
外網驗證訪問,連接不通
$ curl http://192.168.8.190:80 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0 curl: (7) Failed to connect to 192.168.8.190 port 80: Connection refused
Dockerfile中EXPOSE端口
- 結論:Dockerfile中的EXPOSE僅是對端口的聲明,在ps或inspect時顯示,但並不會實際開啟端口的服務,實際端口有容器中程序的端口決定
1. 修改容器web內nginx的端口為88,重啟生效
[root@localhost ~]# docker exec -it web /bin/bash root@9ac59b2d523f:/# vi /etc/nginx/conf.d/default.conf 修改listen參數值為88 [root@localhost ~]# docker restart web web
2.檢查鏡像的Dockerfile文件中Expose的端口:仍為80
[root@localhost ~]# docker history nginx IMAGE CREATED CREATED BY SIZE COMMENT 605c77e624dd 9 days ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B <missing> 9 days ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B <missing> 9 days ago /bin/sh -c #(nop) EXPOSE 80 0B
3.檢查容器信息中顯示的端口:仍為80
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c24aa7848e38 nginx "/docker-entrypoint.…" 39 seconds ago Up 37 seconds 80/tcp web
4.驗證實際可訪問端口。80拒絕連接,88訪問正常
[root@localhost ~]# curl http://172.17.0.2:80 curl: (7) Failed connect to 172.17.0.2:80; 拒絕連接
[root@localhost ~]# curl http://172.17.0.2:88 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> .............. </body> </html>
容器端口映射主機端口
- 結論:若容器未指定主機映射端口,則主機外網絡無法訪問容器,僅本機網絡范圍可訪問。
1. 啟動容器,未指定主機映射端口時
[root@localhost ~]# docker run -d --name web nginx
3cb58fd8e585e0b015e7e42e9587df95359e1d133ff5371c6838fd303132d2ef
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3cb58fd8e585 nginx "/docker-entrypoint.…" 17 seconds ago Up 15 seconds 80/tcp web
外網訪問主機80端口,不通
2. 啟動容器,指定主機映射端口30080映射容器80端口
[root@localhost ~]# docker run -d -p 30080:80 --name web nginx 04ef8440c357b81da934e91e786612b6027d20ea2e7cb3bd81ae91a9ca15a807
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
04ef8440c357 nginx "/docker-entrypoint.…" 8 minutes ago Up 8 minutes 0.0.0.0:30080->80/tcp, :::30080->80/tcp web
外網訪問主機30080,成功
補充:在docker run中使用-p映射端口,在docker-compose中使用-port映射端口,效果相同。
容器間連接
在其他容器中,訪問上方已啟動容器web,容器端口80,映射宿主機端口30080,容器ip:172.17.0.2,主機ip:192.168.8.190
- 總結:容器IP:容器Port,主機IP:主機Port,當ip與port匹配時才能訪問通。
啟動一個redis容器,從redis容器訪問web容器服務。
[root@localhost ~]# docker run -d --name redis redis:6.0.8
[root@localhost ~]# docker exec -it redis /bin/bash
root@25d8d484aa5b:/data# curl http://172.17.0.2:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...........
root@25d8d484aa5b:/data# curl http://172.17.0.2:30080
curl: (7) Failed to connect to 172.17.0.2 port 30080: Connection refused
root@25d8d484aa5b:/data# curl http://192.168.8.190:30080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
............
root@25d8d484aa5b:/data# curl http://192.168.8.190:80
curl: (7) Failed to connect to 192.168.8.190 port 80: Connection refused
補充:若使用docker-compose啟動,且設置了服務依賴,容器ip(172.17.0.2),可以用容器名取代,例如curl http://web:80