首先我們先問幾個問題。
1、docker是怎么訪問互聯網的?
2、互聯網怎么訪問docker的?
3、docker之間是怎么互相訪問的?
4、docker之間又是怎么隔離的?
Docker網絡通訊
docker是怎么訪問互聯網的
我們先來看一下下面這個圖,最低層是我們的宿主機上的eth0網卡,往上一層是docker0網卡(你可以理解為這是一個交換機),然后后面只要我創建一個容器就會多出來一個以veth開頭的網卡。
也就是說默認情況下容器會使用docker0這個網橋,兩個容器都使用這個網橋的話,就可以直接互相訪問了。 然后我們docker的容器里面訪問互聯網的時候,其實就是從veth網卡到docker0轉換,最后經過NAT轉換到我們的宿主機網卡上的。也就是同屬一個docker0網橋下的主機可以互相訪問。
互聯網怎么訪問docker
1、經過前面的學習,我們第一個想到的應該是暴露端口。
下面這個命令是我們經常用的一個創建一個容器的命令,后面的-p的兩個8080的含義是,暴露端口:容器端口,這樣的話我們就可以直接通過宿主機的ip地址加上這個暴露端口就能訪問容器里面的服務了。(這里有個誤區,有人說我一個容器想暴露多個端口怎么辦,首先我不建議你這么做,因為docker的基本概念就是一個容器一個進程,你可以理解為一個容器里面只跑一個單獨的服務)
docker run --name tomcat1 -p 8080:8080 -d tomcat
2、有同學會講,我宿主機有好幾個網卡,我想把端口暴露到指定網卡上怎么辦,如下我們直接簽hostport前面再加上需要綁定網卡的ip地址就行,注意用冒號隔開。
docker run --name tomcat1 -p 192.168.8.120:8080:8080 -d tomcat
3、其它操作
將指定的容器端口映射至主機所有地址的動態端口如下,冒號前的hostport我們不加,但是具體用宿主機上的哪個端口呢,我也不知道。
docker run --name tomcat1 -p :8080 -d tomcat
A同學說上面這個命令可以更簡潔,他有多個網卡,他只想暴露給指定網卡下,如下:
docker run --name tomcat1 -p 192.168.8.120::8080 -d tomcat
B同學說我這台docker宿主機上就跑了這一個docker容器,我嫌棄這映射來映射去麻煩,有辦法。如下,我們直接加一個橫杠大寫的p,這樣我們就把宿主機上的所有端口暴露給了宿主機上,除非你一個容器上運行了很多進程,否則沒必要這么做。
docker run --name tomcat1 -P -d tomcat
4、查詢映射關系
C同學問,我docker上太多的主機了,我也不知道他到底映射了哪些端口,我怎么看?直接使用docker port 容器名稱,就可以看到當前這個容器映射了哪些端口出來了。
[root@localhost ~]# docker port tomcat1 8080/tcp -> 0.0.0.0:80 [root@localhost ~]# docker port tomcat2 8080/tcp -> 0.0.0.0:8080 [root@localhost ~]#
Docker網絡模式修改
1、默認的網橋是docker0,docker0的默認IP地址是172.17.0.1。
2、那既然說了默認,肯定還是可以修改的。
docker進程網絡修改
注意,docker進程網絡修改了以后,凡是加入到這個網橋的容器也就跟着一起改了。注意這里是在創建網橋的時候使用的參數,不是docker run時候用的參數。
-b,--bridge=“ ”,
--bip,手動指定docker0的ip地址和子網掩碼,注意我們一般不指定網橋的時候默認用的是docker0,如果docker0給兩個容器的ip都是一樣的,那他們就沒法通訊了,所以需要此命令指定。例如:--bip 172.16.1.10/24
--dns,指定DNS,前面我們說過docker run的時候也有個--dns的參數,那個設置完了只能是
容器網絡修改
docker run 使用用的參數,也就是說只作用於該容器。
--dns,給該容器配置一個DNS地址。
--net,用於指定網絡通訊,有4個參數,如下:
· host模式,使用--net=host指定。 · container模式,使用--net=container:NAME_or_ID指定。 · none模式,使用--net=none指定。 · bridge模式,使用--net=bridge指定,默認設置。
默認是bridge,所以指不指定意義不大,如果是none 的話,這個容器只有lo網卡(也就是只有本地回環網卡),如果是host的話跟前面說的-P一樣,把該容器的所有端口都暴露給宿主機了,最后是container的話,就相當於兩個容器用的是一個網卡直接localhost就能訪問到另外一個容器的端口。
修改docker0默認ip
A同學說,我老看這個172.17.0.1心里鬧的慌,我要修改一下這個ip。在daemon.json里面加上后docker0網卡ip就變成這個了,然后重啟docker服務,使用docker0網橋的容器也就都變成這個網段了。
常見的隔離方式
前面我們說了一些常用的通訊方式,下面我們說說容器之間怎么來隔離網絡,提高安全呢。
1、默認不指定的話,容器使用的是docker0網橋,同一個網橋上容器之間是可以互相訪問的。我們可以創建多個網橋,指定容器使用不同的網橋來進行容器間的隔離。
這里我們需要學習一個命令
docker network ls #查看當前主機上的所有網橋,默認有bridge、none、host,可以自行添加
創建網橋
docker network create -d 網絡類型 網絡空間名稱(自己起名)
網絡類型分為兩種,一種是bridge就是我們前面用的橋接,另外一種是overlay,overlay配合第三方插件可以實現不同主機之間的容器通訊,這里我們先不說,有興趣的通訊自己百度一下。
結論:使用不同網橋的兩個容器,可以訪問互聯網,但是容器之間是無法訪問的。
A同學問,你說的這網橋就這么直接創建了,我怎么指定網橋用的ip地址類型和網段呢,如下命令:
docker network create -d bridge --subnet "192.168.110.0/24" --gateway "192.168.110.1" lnmp
創建兩個不同網段的bridge網橋
然后我們創建兩個tomcat容器,分別使用lnmp和lamp網橋。
容器已經啟動
我們可以看到使用兩個不同的網橋的容器分別分到了自己應該分到的網段和ip,而且都能上百度,但是容器之間有進行了隔離。
跨主機通信
docker不同宿主機之間通訊分為三個方向,路由、橋接(如pipework)、overlay(如flannel)。下面我們先看看pipwork的設置方法。
環境介紹:
宿主機1:centos7.7 docker:17.03.0-ce IP:192.168.8.119
宿主機2:centos7.7 docker:17.03.0-ce IP:192.168.8.120
實驗目標:
實現兩台宿主機上的docker容器能夠互相訪問。
宿主機1:
1、設置橋接網卡,你也可以直接用命令創建。
#cd /etc/sysconfig/network-scripts/ #cp -a ifcfg-ens33 ifcfg-br0
將原有ifcfg-ens33網卡里面的ip、網關、子網掩碼、dns都去掉,新加一個BRIDGE=br0即可。

TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=bd522766-775c-4d10-8933-9061ac412d13 DEVICE=ens33 ONBOOT=yes BRIDGE=br0
編輯ifcfg-br0網卡,這里我們要訪問外網下載工具,所以網關和DNS我都加上了。

DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.8.119 NETMASK=255.255.255.0 GATEWAY=192.168.8.1 DNS1=192.168.8.1
2、下載pipework命令,啟動一個測試容器,用pipework給容器單獨設置和宿主機同個網段的ip。
#下載git命令 yum install -y git #下載pipework工具 git clone https://github.com/jpetazzo/pipework #將pipework命令拷貝到/usr/local/bin/下 cp pipework/pipework /usr/loca/bin/ #設置可執行權限 chmod a+x /usr/local/bin/pipework #這里我們用tomcat測試 docker pull tomcat #啟動一tomcat容器,這里網絡我們先設置none,后面再給他單獨設置。 docker run --name tomcat --net=none -d tomcat #如下:tomcat這個名氣就是我們上面啟動的容器名字,ip地址是跟宿主機一個網段的ip pipework br0 tomcat 192.168.8.118/24
3、測試如下:等同於給tomcat這個容器設置了一個同宿主機一個網段的ip,這樣最大的一個問題是同一個網段的ip地址有限。不適合大規模使用。
宿主機2:
1、設置橋接網卡,你也可以直接用命令創建。
#cd /etc/sysconfig/network-scripts/ #cp -a ifcfg-ens33 ifcfg-br0
將原有ifcfg-ens33網卡里面的ip、網關、子網掩碼、dns都去掉,新加一個BRIDGE=br0即可。

TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=cc083d6b-2bf1-4ca3-b9c8-1f5f10f01b3c DEVICE=ens33 ONBOOT=yes BRIDGE=br0
編輯ifcfg-br0網卡,這里我們要訪問外網下載工具,所以網關和DNS我都加上了。

DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.8.120 NETMASK=255.255.255.0 GATEWAY=192.168.8.1 DNS1=192.168.8.1
2、下載pipework命令,啟動一個測試容器,用pipework給容器單獨設置和宿主機同個網段的ip。
#下載git命令 yum install -y git #下載pipework工具 git clone https://github.com/jpetazzo/pipework #將pipework命令拷貝到/usr/local/bin/下 cp pipework/pipework /usr/loca/bin/ #設置可執行權限 chmod a+x /usr/local/bin/pipework #這里我們用tomcat測試 docker pull tomcat #啟動一tomcat容器,這里網絡我們先設置none,后面再給他單獨設置。 docker run --name tomcat --net=none -d tomcat #如下:tomcat這個名氣就是我們上面啟動的容器名字,ip地址是跟宿主機一個網段的ip pipework br0 tomcat 192.168.8.121/24
3、測試如下:等同於給tomcat這個容器設置了一個同宿主機一個網段的ip,這樣最大的一個問題是同一個網段的ip地址有限。不適合大規模使用。
總結
1、度娘說pipework不是自動執行的命令,重啟失效,所以我們要給他設置開機自動運行,但是實測根本不行,重啟完以后就設置的開機自啟動生效不了,還是需要手動執行pipework命令。可以給容器設置--restart=always參數,讓他根據docker服務器啟動以后自動啟動。如果已經啟動容器不想重啟,可以直接使用update命令。docker update --restart=always tomcat
2、這種方式適合小型環境,容器啟動以后自己再挨個執行命令(可以寫到一個腳本文件里面,執行一個腳本,容器的ip就都配置好了),大型環境就慘了。
3、ip地址不夠用也是一個問題,同一個網段254個ip,如上2所說,這種也不可能到254容器,那只是配置ip都要瘋了。
docker自帶的overlay
需要注意使用overlay網絡有2中模式一個是swarm模式,一個是非swarm模式,在非swarm模式下使用則需要借助服務發現第三方組件。
docker實現跨主機通信需要的網絡驅動類型為overlay,但是同時還需要一個鍵值型的服務發現和配置共享軟件,比如Zookeeper、Doozerd、Etcd、Consul等。Zookeeper、Doozerd、Etcd在架構上很類似,只提供原始的鍵值存儲,要求程序開發人員自己提供服務發現功能,而Consul則內置了服務發現,只要用戶注冊服務並通過DNS或HTTP接口執行服務發現即可,同時它還具有健康檢查功能。我們這里使用Consul來作為服務發現工具。先說一下環境:
宿主機1:192.168.8.119 centos7.7
宿主機2:192.168.1.120 centos7.7
docker:17.03.0-ce
關閉iptables、firewalld、selinux服務。
准備環境:
這里我們停用firewall和selinux、如果有iptables也建議先停止服務。
1、安裝Consul
通常我們應該單獨找一台主機,專門做Consul服務,這里我們就直接在8.119上面安裝。
#wget https://releases.hashicorp.com/consul/1.7.2/consul_1.7.2_linux_386.zip #yum install -y unzip #unzip consul_1.7.2_linux_386.zip #mv consul /usr/bin/ && chmod a+x /usr/bin/consul #nohup consul agent -server -bootstrap -ui -data-dir /data/docker/consul -client=192.168.8.119 -bind=192.168.8.119 &> /var/log/consul.log
2、節點配置Dockre守護進程連接Consul,
宿主機1:去配置文件中修改內容
# vim /lib/systemd/system/docker.service
修改ExecStart參數
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.8.119:8500 --cluster-advertise 192.168.8.119:2375
最后重新加載服務
systemctl daemon-reload systemctl restart docker
宿主機2:去配置文件中修改內容
# vim /lib/systemd/system/docker.service
也是修改ExecStart參數,但是注意consul://192.168.8.119:8500這個ip地址要寫Consul的地址,這里指的是宿主機1的ip
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.8.119:8500 --cluster-advertise 192.168.8.120:2375
最后重新加載服務
systemctl daemon-reload systemctl restart docker
3、查看consul 中的節點信息
4、在宿主機1上創建overlay網絡
然后宿主機2也會自動同步這個操作。
宿主機1:
docker run --name tomcat --net=overlay -d tomcat
宿主機2:
docker run --name tomcat11 --net=overlay -d tomcat
注意:
這里我們在宿主機1上已經創建了tomcat這個名字的docker容器了,在宿主機2上創建docker容器的時候不能再叫tomcat這個名字了,docker提示已經有叫tomcat這個名字的容器了。所以我們需要改個名字。
首先創建完tomcat和tomcat11兩個容器以后,宿主機1和宿主機2上都會生成一個網卡docker_gwbridge網卡。
宿主機1:
宿主機2:
最后我們分別登陸到宿主機1上的tomcat容器和宿主機2上的tomcat11容器里面看一下。
宿主機1上的tomcat容器:
宿主機2上的tomcat11容器:
補充:
前面我們看到每個宿主機上創建完overlay的容器以后,會多出來一個docker_gwbridge網卡,然后我們進入容器以后,會發現除了有一個跟docker_gwbridge同網段的ip外,也就是eth1xxx網卡,還有一個eth0xxx的網卡,這個ip地址是10.0.0.x網段的。這eth0網卡上的ip地址是用於跨主機之間互相通信的ip地址,而eth1xxx這個網卡上的ip地址是用於訪問互聯網和外網訪問的的。
1、一定要記住這個eth0的網卡只能用戶跨主機容器之間的互相訪問。
2、eth1這個網卡(也就是docker_gwbridge同個網段的網卡)是用戶訪問互聯網和被互聯網訪問的。這里說的能被互聯網訪問是要在啟動容器的時候加-p參數,但是,但是,但是如下。
3、如果安裝上面那樣外面肯定訪問不了,首先我們要加-p參數,如下:
docker run --name tomcat111 -p 8080:8080 --net=overlay -d tomcat
如果你直接運行這個啟動容器命令肯定會報錯。
driver failed programming external connectivity on endpoint gateway_86200ff523bb...........................................
在daemon.json里面關閉防火牆接口,如下操作
vim /etc/docker/daemon.json
重啟docker服務,然后再運行啟動命令 #systemctl restart docker
總結:
根據上面的演示,我們得出如下:
1、使用overlay模式進行互通的話,每個容器有兩個網卡,一個是只能是不同宿主機上的容器之間通信,也就是eth0xxxxx,超過254個容器就完犢子了。
2、每個容器除了說的用戶不同主機之間互訪的網卡外,還會生成一個網卡,也就是eth1xxxx,這個網卡是專門用戶訪問互聯網和被互聯網訪問的,
3、eth1xxxx這個訪問互聯網的網卡也不是直接就能被互聯網訪問,需要啟動容器的使用用-p指定映射端口,而且前提是需要在daemon.json里面把iptables設置成false,重啟docker服務才行。
4、每個容器都有兩個網卡,這要是容器多了,呵呵,你細品,細細的品。