一、概述
參看文章:https://docs.docker.com/engine/reference/commandline/network_create/
Docker自身的4種網絡工作方式,和一些自定義網絡模式
安裝Docker時,它會自動創建三個網絡,bridge(創建容器默認連接到此網絡)、 none 、host
host:容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。
Container:創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口范圍。
None:該模式關閉了容器的網絡功能。
Bridge:此模式會為每一個容器分配、設置IP等,並將容器連接到一個docker0虛擬網橋,通過docker0網橋以及Iptables nat表配置與宿主機通信。
以上都是不用動手的,真正需要配置的是自定義網絡。
二、網絡介紹
2.1、網絡設置
當你安裝Docker時,它會自動創建三個網絡。你可以使用以下docker network ls命令列出這些網絡:
$ docker network ls NETWORK ID NAME DRIVER 7fca4eb8c647 bridge bridge 9f904ee27bf5 none null cf03ee007fb4 host host
Docker內置這三個網絡,運行容器時,你可以使用該--network標志來指定容器應連接到哪些網絡。
該bridge網絡代表docker0所有Docker安裝中存在的網絡。除非你使用該docker run --network=<NETWORK>選項指定,否則Docker守護程序默認將容器連接到此網絡。
我們在使用docker run創建Docker容器時,可以用 --net 選項指定容器的網絡模式,Docker可以有以下4種網絡模式:【bridge host ipvlan macvlan null overlay】
host模式:使用 --net=host 指定。
none模式:使用 --net=none 指定。
bridge模式:使用 --net=bridge 指定,默認設置。
container模式:使用 --net=container:NAME_or_ID 指定。
2.2、host網絡
與宿主機在同一個網絡中,但沒有獨立IP地址。眾所周知,Docker使用了Linux的Namespaces技術來進行資源隔離,如PID Namespace隔離進程,Mount Namespace隔離文件系統,Network Namespace隔離網絡等。一個Network Namespace提供了一份獨立的網絡環境,包括網卡、路由、Iptable規則等都與其他的Network Namespace隔離。一個Docker容器一般會分配一個獨立的Network Namespace。但如果啟動容器的時候使用host模式,那么這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。
例如,我們在10.10.0.186/24的機器上用host模式啟動一個含有nginx應用的Docker容器,監聽tcp80端口。
# 運行容器; $ docker run --name=nginx_host --net=host -p 80:80 -d nginx 74c911272942841875f4faf2aca02e3814035c900840d11e3f141fbaa884ae5c # 查看容器; $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 74c911272942 nginx "nginx -g 'daemon ..." 25 seconds ago Up 25 seconds nginx_host
當我們在容器中執行任何類似ifconfig命令查看網絡環境時,看到的都是宿主機上的信息。而外界訪問容器中的應用,則直接使用10.10.0.186:80即可,不用任何NAT轉換,就如直接跑在宿主機中一樣。但是,容器的其他方面,如文件系統、進程列表等還是和宿主機隔離的。
$ netstat -nplt | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 27340/nginx: master
小結:
直接使用宿主機的 IP 地址,最簡單,但是容器跟宿主機共享,直接對外暴露,安全性低。
Docker 17.06+ 支持。
僅支持 Linux。
2.3、Container
在理解了host模式后,這個模式也就好理解了。這個模式指定新創建的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口范圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過lo網卡設備通信。
2.4、None
該模式將容器放置在它自己的網絡棧中,但是並不進行任何配置。實際上,該模式關閉了容器的網絡功能,在以下兩種情況下是有用的:容器並不需要網絡(例如只需要寫磁盤卷的批處理任務)。禁用網絡配置,通常是在使用第三方網絡配置插件時設置。
2.5、overlay
在docker1.7代碼進行了重構,單獨把網絡部分獨立出來編寫,所以在docker1.8新加入的一個overlay網絡模式。Docker對於網絡訪問的控制也是在逐漸完善的。
docker 自帶的跨主機網絡模型
2.6、Bridge
相當於Vmware中的Nat模式,容器使用獨立network Namespace,並連接到docker0虛擬網卡(默認模式)。通過docker0網橋以及Iptables nat表配置與宿主機通信;
bridge模式是Docker默認的網絡設置,
當docker服務啟動后,會創建一個名字叫docker0的虛擬網橋,然后選一個與宿主機不一樣的網絡ip地址以及子網分配給docker0
另外每創建一個容器就會新增一個容器網卡,此模式會為每一個容器分配Network Namespace、設置IP等,然后以橋接方式架到docker0網橋中,docker0會以NAT地址轉換的方式通過宿主機的網卡,從而與公網進行通信。
2.6.1、修改Docker0網橋默認網段
它在內核層連通了其他的物理或虛擬網卡,這就將所有容器和本地主機都放到同一個物理網絡。
Docker 默認指定了 docker0 接口 的 IP 地址和子網掩碼,讓主機和容器之間可以通過網橋相互通信,它還給出了 MTU(接口允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機網絡路由上支持的默認值。這些值都可以在服務啟動的時候進行配置。
1、默認 docker0 網橋信息
ifconfig docker0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:db:0d:17:0c txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2、修改文件 /etc/docker/daemon.json 添加內容 "bip": "ip/netmask" [切勿與宿主機同網段]
vim /etc/docker/daemon.json { "bip":"192.168.100.1/24" }
3、重啟服務並查看
systemctl restart docker
或者:service docker restart 執行步驟一查看網卡信息
2.7、macvlan
macvlan 網卡虛擬化技術,可以在一張物理網卡上配置多個 MAC 地址,對應多個 interfaces,每個 interface 一個ip。優點是性能極好,不需要創建Linux bridge,而是直接通過interface連接到物理網絡。
Docker 中,可以為每個容器分配一個 MAC 地址,直接通過 MAC 地址轉發數據。
需要考慮網絡性能時,或者希望應用直接通過 物理網卡連接到網絡時可以使用。
2.8、多docker通訊
參看:https://www.cnblogs.com/jayhou/p/12319655.html
三、Bridge詳解
Docker 默認設置的網絡模式
3.1、Linux和mac網絡實現
linux系統:
-
- Docker 宿主機創建一個 docker0網卡, 隨機分配一個本地未占用的私有網段,e.g: 172.17.0.1/16;
- Docker 容器會增加一個 eth0 的網卡,隨機分配同一網段: e.g 172.17.0.0/16 中的一個 ip.
- 當 Docker 創建一個容器時,同時會創建了一對 veth pair 接口(當數據包發送到一個接口時,另外一個接口也可以收到相同的數據包)。這對接口一端在容器內,即 eth0;另一端在本地並被掛載到 docker0 網橋,名稱以 veth 開頭(例如 vethAQI2QT)。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。Docker 就創建了在主機和所有容器之間一個虛擬共享網絡。
ifconfig | grep docker -A 8
ifconfig | grep eth0 -A 7
mac系統:
因為實現的方式不同(見下),所以沒有 docker0 網卡。
3.1.1、Linux 和 Mac 網絡的區別
1、Linux 下的網絡結構【下圖1】
Docker 在 Linux 的自帶內核上實現的,所以 Docker 在 Linux 上安裝后, 會創建一個 docker0 的虛擬網卡,Linux 宿主機和 Docker 中的容器通過該網卡進行通信。
2、Mac 下的網絡結構: 【上圖2】
Docker 在 Mac 中的實現是通過 Hypervisor 創建一個輕量級的虛擬機,然后 將 docker 放入到虛擬機中實現。Mac OS 宿主機和 Docker 中的容器通過 /var/run/docker.sock 這種 socket 文件來通信,所以在 Mac OS 中 ping 容器的 IP,在容器中 ping 宿主機的 IP 就不通。
四、Docker 在 Mac 中的兩種實現方式
docker 在 Mac 中有兩種實現,一種是基於 HyperKit (Docker Desktop for Mac),另一種是基於Virtual Box(Docker Toolbox).
兩者的區別會導致宿主機和容器直接網絡訪問方式不同,Docker Desktop for Mac 是基於 /var/run/docker.sock 文件。Docker Toolbox 是基於虛擬網卡。還有就是管理容器的方式不一樣, Docker Desktop for Mac 是使用 HyperKit, 基於 Hypervisor 的輕量級虛擬化機;Docker Toolbox 則是使用 Virtual Box 創建虛擬機的方式來創建容器。
4.1、Docker Desktop for Mac
4.1.1、宿主機和容器的端口映射
docker run -p HOST_PORT:CLIENT_PORT xxxxx
e.g : doker run -p 80:80 -d nginx
4.1.2、Mac OS 中的限制
沒有 docker0 bridge 網卡。
宿主機不能 ping 通容器的ip,宿主機
不能從主機 Mac 訪問 Linux bridge.
4.1.3、mac 宿主機 和 容器互通 的解決方案
1、容器內訪問宿主機,在 Docker 18.03 過后推薦使用 特殊的 DNS 記錄 host.docker.internal 訪問宿主機。但是注意,這個只是在 Docker Desktop for Mac 中作為開發時有效。 網關的 DNS 記錄: gateway.docker.internal。原文 Docker for Mac
2、宿主機訪問容器,使用本機 localhost 端口映射功能,使用 –publish(單個端口), -p(單個端口), -P(所有端口) 將本機的端口和容器的端口映射。
3、宿主機訪問容器,使用 -p 參數映射端口。容器訪問宿主機,可以在宿主機使用下面的命令獲取 宿主機的 ip 地址:
ps -ef | grep -i docker | grep -i "\-\-host\-ip" |awk -F "host-ip" '{print $2}' | awk -F '--lowest-ip' '{print $1}'
在宿主機的 mac 上查看 docker deamon的進程,可以找到啟動的配置參數如下
ps -ef |grep -i docker
--host-ip
從進程中可以提取到宿主機的 ip 地址,這個 ip 地址的網段在 Docker for Mac –> Preferences – > Advanced –> Docker subnet 中配置。
舊版本 使用比較麻煩,新版本直接配置,網路可通
可以在容器中安裝 Rinetd 來轉發本地的 socket 請求到宿主機。
4.2、Docker Toolbox
目的是為了適配老版本的 Mac OS 和 Windows,實現方式和 Docker Desktop for Mac 不同。