Docker單機中三種網絡模型的簡單理解

那些年接觸的網絡模型

平常開發中,接觸最先的是虛擬機(vmware, virtualbox)裏的網絡模型。而在docker下的網絡模型(networkdriver)是docker架構中處理網絡虛擬化的重要部分,主要默認的能夠看到有如下三種。html

root@volvo:/etc# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
7235d2d26f6f        bridge              bridge              local
7ea4e817d5fd        host                host                local
1a445ef4688b        none                null                local

另外docker還有Containeroverlaymacvlanoverlay主要是基於多個docker host之間(通常是多個宿主機之間)。其中macvlan是基於虛擬物理地址的mac地址(須要開啓網卡的混雜模式promiscuous mode,且支持vlan)的模式。這裏主要說單機模式的最多見的以上三種。node

如下操做環境爲 Ubuntu 20.04 LTS,若是採用 win或者 macdocker desktop。結果可能沒法正常運行~。另外建議你們直接面向 官方文檔編程^_^。

virtual box 的網絡模式

回顧如下咱們以前用到的最可能是虛擬機(這裏指virtualbox vmware),他們有如下幾種經常使用網絡模式:linux

  • image.png
  • 橋接網絡bridge:虛擬機之間能夠互通,虛擬機物理機也能夠互通。且默認均可以訪問外網。
  • 網絡地址轉換nat:虛擬機所在的網絡和物理機不在同一個網段,且(虛擬)網絡設備互相隔離。也就是說虛擬機之間不通,可是和物理機能夠通,虛擬機經過物理機也能夠上網。
  • nat網絡:與nat最大不一樣是(虛擬)網絡設備是共享的,且在一個網段內,也就說虛擬機之間是全通的。通常也會啓動一個dhcp服務。另外是nat和nat網絡的相同點主機內都不能ping通虛擬機的(能夠經過端口映射這個功能實現)
  • 僅主機host-only模式:一樣虛擬機之間能夠互通,至關於在一個網絡裏。

docker內none網絡

none網絡,表明使用容器自身網絡,與世隔絕,本身在小黑屋high的。可能用到的場景爲是涉及到安全、數據清洗、內部erp之類(我yy的)。參考例子以下:(--rm 表明運行完容器自清理,-ti表明交互模式,並開啓一個終端,docker run更多命令解析)nginx

docker run --name busyboxNoneNet --rm -it --network=none busybox
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

docker內host網絡

直接上代碼git

docker run  --name 1busyboxHostNet -it --network=host busybox

host網絡會看到宿主機的全部網絡,注意是全部。這個名字雖然叫host,主機內網絡能看到的,在容器內都能看到且訪問到。可是主機向容器內訪問不到,容器ping 主機ip能夠。
一些特色:github

  • 在容器內執行hostname,發現和宿主機是同樣的【可是注意權限有明確區分】
  • 執行ps -ef命令或者cat /etc/user 命令,容器內與宿主機就不一樣了。能夠看出除了 Net和user沒有隔離, user ,pid,mount ,ipc都進行了隔離。
  • 以上兩點參考如下代碼
#宿主機
root@volvo:/home/tb# hostname
volvo
root@volvo:/home/tb# ps -aux |wc -l
306
root@volvo:/home/tb# 
root@volvo:/etc# ls |wc -l
223
root@volvo:/etc# cat /etc/hosts
127.0.0.1    localhost
127.0.1.1    volvo

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
#容器內
/ # hostname
volvo
/ # ps -a
PID   USER     TIME  COMMAND
    1 root      0:00 sh
   10 root      0:00 ps -a
/ # cd etc/
/etc # ls
group        hostname     hosts        localtime    mtab         network      passwd       resolv.conf  shadow
/etc # 
/etc # cat /etc/hosts
127.0.0.1    localhost
127.0.1.1    volvo

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
/etc #
  • host其餘注意事項docker

    • host容器和宿主機的端口可能會產生衝突,好比容器內監聽了80,實際上宿主機的80端口也被佔用了。
    • 使用host模式的容器不會被分配ip地址(容器通訊的 IP 地址即爲宿主機的地址)。能夠用如下命令見證:編程

      docker run --rm -d --network host --name myNginxHostNet nginx
      root@volvo:/home/tb# docker inspect myNginxHostNet -f {{.NetworkSettings.Networks.bridge~~~~.IPAddress}}
      <no value>
Tips:爲了作實驗,防止docker pull的鏡像慢,我這貼一個 docker register source^_^, vim /etc/docker/daemon.json添加以下,記得重啓 systemctl restart docker
{
   "registry-mirrors": [
   "https://kfwkfulq.mirror.aliyuncs.com",
   "https://2lqq34jg.mirror.aliyuncs.com",
   "https://pee6w651.mirror.aliyuncs.com",
   "https://registry.docker-cn.com",
   "http://hub-mirror.c.163.com"
   ],
   "dns": ["8.8.8.8","8.8.4.4"]
   }
  • 驗證host模式

訪問:http://192.168.1.9/ 宿主機查看:json

root@volvo:/etc# netstat -anp |grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      23113/nginx: master 
tcp        0      0 192.168.1.9:80          192.168.1.32:52389      ESTABLISHED 23141/nginx: worker

docker內bridge網絡

bridge 都幹了啥

docker自己有就存在一個默認的bridge(如最開始咱們看到的),用戶也能夠自定義建立的self-bridge(經過docker create network xx)。bridge模式是單體宿主機中用於容器通訊最經常使用的方式。Docker bridge` 模式實現基於虛擬機中使用的 NAT 方式以及docker proxy。nat基於linux的即veth pair。簡單的說就是docker daemon下配置一個docker0的虛擬網橋,一邊鏈接宿主機,一邊連着N多的容器。而後宿主機上會建立一對虛擬的網絡接口 veth pair(這個東西能夠理解爲鏈接兩個net namespace的橋樑)
若是須要宿主機和容器之間通訊,則veth pair的一邊掛在docker0上,另外一邊掛在不一樣的container中。vim

image.png

若是容器要鏈接外網以及外網到達容器內,那麼就是咱們通常概念中的的nat,而docker中最多見的就是端口映射(natp),natp能夠根據數據包的進出順序分爲snat(source nat)和dnat(destination nat)。當前這裏面docker 還操做了好比iptable,route相關的操做,具體又能夠拿來講說了。。仍是舉個簡單的例子吧先:好比外界須要訪問docker內容器,

  • 大洋彼岸網絡要訪問嘎子村中起的一個nginxdocker服務.(前提nginx docker已經暴露了給宿主機80,即常見的expose Port 80:80),流程簡單理解以下:
  • 大洋彼岸(公網ip)--> 嘎子村(公網ip:80)--> 宿主機docker0網橋--> docker0:veth0->【veth pair】--> docker nginx:80(即veth1)。以上爲docker經過natp的方式修改了包的目的地址(修改目的地址爲dnat),數據經過容器返回給外部的過程就須要snat
  • 以上例子同時涉及網橋接口的通訊(brctl show)、iptable的一些規則(iptables -t nat -vnL)以及內核層面的數據包轉發(cat /proc/sys/net/ipv4/ip_forward),這裏就不具體說了,由於我也沒實際操做。能夠具體用wireshark或者tcpdump去看看~

是用默認的 bridge仍是本身造一個?

另外docker bridge中官方文檔,特別指出: 若是使用默認的的bridge網絡,容器之間只能用ip,而不能用container Name(除非你顯示指定 --link,然而這個link(實際就是在host中增長一條指向)在後期可能就被廢掉),並且全部的容器之間默認均可以直接通訊,這也是一個風險點。另外若是你想把一個容器放到其餘網絡,若是你使用默認的bridge,那你只能先停掉,在修改network,再啓用,至關繁瑣。因此官方建議使用自建的bridge,本身定義的bridge就直接兩條命令實現容器和網絡之間的關閉和鏈接,另一點使用本身建立的bridge ,默認直接可使用container name來訪問,無需link了。另外使用自定義的bridge還能夠分別自定義不一樣子網的網橋的子網掩碼,mtu大小,iptable規則等。

bridge的實際例子

咱們先看一下本機網卡配置

root@volvo:/home/tb# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether d8:c4:97:0f:4b:c2 brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether e8:2a:44:f1:fc:61 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.9/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp3s0
       valid_lft 244150sec preferred_lft 244150sec
    inet6 240e:82:2:cf9:cdf4:d5ce:b3b3:c6fe/64 scope global temporary dynamic 
       valid_lft 258761sec preferred_lft 71149sec
    inet6 240e:82:2:cf9:f5fb:539d:7ef6:5ee2/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 258761sec preferred_lft 172361sec
    inet6 fe80::51b0:b9d3:fa60:7dc6/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:d3:86:73:83 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d3ff:fe86:7383/64 scope link 
       valid_lft forever preferred_lft forever

這裏一共四塊網卡,docker0lo沒必要說,enp2s0wlan分別表明物理網卡和無線網卡,我這裏是用wlan
咱們分別啓動兩個container,注意默認爲bridge模式。

docker run --name demo1 --rm -it busybox /bin/sh
docker run --name demo2 --rm -it busybox /bin/sh

再次宿主機中執行ip a發現多了兩塊。注意編號分別爲14,16記住這兩個數字

14: vethf42774d@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 7e:df:8d:d4:54:a0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::7cdf:8dff:fed4:54a0/64 scope link 
       valid_lft forever preferred_lft forever
 16: veth21a33a9@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ca:35:58:9b:0e:77 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::c835:58ff:fe9b:e77/64 scope link

分別在demo1和demo2容器內執行 ip a

  • demo2中:

    / # ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
       link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
       inet 127.0.0.1/8 scope host lo
          valid_lft forever preferred_lft forever
    13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
       link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
       inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
          valid_lft forever preferred_lft forever
  • demo1中爲【eth0@if16】

    # ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever

而後咱們在宿主機上查看一下網橋信息 ,具體的對應關係能夠參考上面的【13,15】 【14,16】去查找。好比宿主機中的14號顯示和13作關聯,那麼13就表明某一個容器內的網卡編號,而這個容器內的網卡也會關聯到宿主機的14。(brctl自己也能夠建立網橋,綁定網卡,設置網關、子網掩碼等,只不過docker把這些動做至關於都封裝了)

root@volvo:/home/tb# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.0242d3867383    no        veth21a33a9
                                         vethf42774d

咱們停掉demo1以後,再宿主機上查看 ip a,會發現網卡已經少了一個

...
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:d3:86:73:83 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d3ff:fe86:7383/64 scope link 
       valid_lft forever preferred_lft forever
14: vethf42774d@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 7e:df:8d:d4:54:a0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::7cdf:8dff:fed4:54a0/64 scope link 
       valid_lft forever preferred_lft forever
root@volvo:/home/tb#

固然你以爲這裏很亂也沒有關係,早已經有大神簡單實現了這個配對的尋找辦法。這裏有個小工具dockerveth,不用肉眼識別,直接一把梭。

後序

docker的網絡與容器之間能夠任意搭配,咱們能夠根據業務狀況建立本身的bridge,並且能夠配置cidrgateway 等,但以上介紹的模式是基礎,是小打小鬧,本身測試環境拿來玩玩兒還能夠,在真正的生產環境,是須要跨主機甚至跨平臺的,並且機器數量巨大,經過nat這種方式不能知足GDP的快速增長。。利用overlay等技術實現跨宿主機、跨平臺的的docker之間的透明通訊纔是咱們應該去掌握的。後序會結合swarm和k8s看是如何調度通訊的。

參考資料

  1. 企業級微服務實戰
  2. 容器網絡隔離技術
  3. docker-proxy存在合理性分析
  4. iptables詳解
  5. linux veth pair
相關文章
相關標籤/搜索