聊聊docker那些埠問題

鍾靈.毓秀發表於2022-01-08

今天來系統聊一聊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

相關文章