博文大綱:
1、前言
2、Docker的原生網絡
3、自定義bridge網絡
4、實現docker跨主機通訊
5、使外網能夠訪問容器的方法nginx
因爲docker技術的火爆,致使如今愈來愈多的企業都在使用docker這種虛擬化技術。企業中使用docker這種虛擬化技術,其目的就是爲了讓docker中的容器對外提供服務。所以,咱們必須深刻了解一下docker的網絡知識,以知足更高的網絡需求。web
當你安裝Docker時,它會自動建立三個網絡。以下:docker
[root@localhost ~]# docker network ls //查看docker的默認網絡 NETWORK ID NAME DRIVER SCOPE a38bd52b4cec bridge bridge local 624b3ba70637 host host local 62f80646f707 none null local
Docker內置這三個網絡,運行容器時,你可使用該「--network」選項來指定容器應鏈接到哪些網絡。若是沒有指定則默認使用bridge模式。bootstrap
好比:vim
host模式:使用 --net=host 指定; none模式:使用 --net=none 指定; bridge模式:使用 --net=bridge 指定(默認設置);
下面詳細介紹一下這幾種網絡模式:瀏覽器
雖然docker模式提供三種網絡模式,但實際上是有四種網絡模式的!安全
若是啓動容器時使用host模式,那麼這個容器將不會得到一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。 服務器
使用場景:網絡
因爲網絡配置與docker宿主機徹底同樣,性能較好,可是不便之處就是靈活性不高,容易和宿主機出現端口衝突的問題。最好是單個容器時使用,通常狀況下不建議使用。tcp
建立使用host網絡模式的容器示例:
[root@localhost ~]# docker run -it --name host --network host busybox:latest //使用busybox鏡像建立一個名爲host的容器,網絡採用host模式 / # ip a //進入容器後能夠看出容器中的網絡與docker主機的網絡如出一轍 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:66:72:13 brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global ens33 valid_lft forever preferred_lft forever inet6 fe80::9f3:b94e:5f5d:8070/64 scope link valid_lft forever preferred_lft forever 3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue qlen 1000 link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 valid_lft forever preferred_lft forever 4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 qlen 1000 link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff 5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue link/ether 02:42:3c:06:f8:1d 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
在none模式下,Docker容器擁有本身的Network Namespace,可是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。須要咱們本身爲Docker容器添加網卡、配置IP等。
使用場景:
none模式被稱爲隔離的網絡,隔離便意味着安全,不能與外部通訊,一樣外部也不能夠訪問到使用none模式的容器,使用這種網絡模式的容器能夠運行於關於安全防面的驗證碼、校驗碼等服務。
通常用於對安全性要求較高的場景中!
建立使用none網絡模式的容器示例:
[root@localhost ~]# docker run -it --name none --network none busybox:latest //使用busybox鏡像建立一個名爲none的容器,網絡採用none模式 / # ip a //能夠看到容器中只有一個lo網卡 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
bridge模式是Docker默認的網絡設置,此模式會爲每個容器分配Network Namespace、設置IP等,並將一個主機上的Docker容器鏈接到一個虛擬網卡上。當Docker server啓動時,會在主機上建立一個名爲docker0的虛擬網橋,此主機上啓動的Docker容器會鏈接到這個虛擬網橋上。虛擬網橋的工做方式和物理交換機相似,這樣主機上的全部容器就經過交換機連在了一個二層網絡中。接下來就要爲容器分配IP了,Docker會從RFC1918所定義的私有IP網段中,選擇一個和宿主機不一樣的IP地址和子網分配給docker0,鏈接到docker0的容器就從這個子網中選擇一個未佔用的IP使用。如通常Docker會使用172.17.0.0/16這個網段,並將172.17.0.1/16分配給docker0網橋。
[root@localhost ~]# 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:3c:06:f8:1d 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 [root@localhost ~]# brctl show //查看橋接網絡 bridge name bridge id STP enabled interfaces docker0 8000.02423c06f81d no //若是沒有建立橋接模式的容器,默認是空的。
建立使用bridge網絡模式的容器示例:
[root@localhost ~]# docker run -itd --name bridge busybox:latest /bin/sh //建立一個名爲bridge的容器,若是沒有指定網絡模式,默認即是bridge模式 [root@localhost ~]# docker exec -it bridge /bin/sh //進入bridge容器中 / # 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 6: eth0@if9: <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 //能夠看出eth0@if9這塊虛擬網卡上的地址與docker宿主機的docker0網絡屬於同一網段 [root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02423c06f81d no veth811d20c //能夠看到橋接模式的接口下出現了一個新的接口,當建立一個容器便會出現一個接口 //這個接口即是容器在docker宿主機建立一個虛擬網卡,用於容器與docker通訊 [root@localhost ~]# ifconfig veth811d20c //查看這個虛擬網卡是否存在 veth811d20c: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::c035:95ff:febf:978b prefixlen 64 scopeid 0x20<link> ether c2:35:95:bf:97:8b txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 648 (648.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
當使用bridge網絡模式,docker的工做步驟大體爲:
(1)在主機上建立一對虛擬網卡veth pair設備。veth設備老是成對出現的,它們組成了一個數據的通道,數據從一個設備進入,就會從另外一個設備出來。所以,veth設備經常使用來鏈接兩個網絡設備;
(2)Docker將veth pair設備的一端放在新建立的容器中,並命名爲eth0。另外一端放在主機中,以veth811d20c這樣相似的名字命名,並將這個網絡設備加入到docker0網橋中,能夠經過brctl show命令查看(上述實例已經驗證);
(3)從docker0子網中分配一個IP給容器使用,並設置docker0的IP地址爲容器的默認網關;
這個模式指定新建立的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新建立的容器不會建立本身的網卡,配置本身的IP,而是和一個指定的容器共享IP、端口範圍等。一樣,兩個容器除了網絡方面,其餘的如文件系統、進程列表等仍是隔離的。兩個容器的進程能夠經過lo網卡設備通訊。
建立使用container網絡模式的容器示例:
[root@localhost ~]# docker run -it --name container --network container:a172b832b531 busybox:latest //a172b832b531是bridge容器的ID號 / # 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 8: eth0@if9: <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 //能夠看出container容器的IP地址與bridge容器的IP地址如出一轍
關於這四種網絡模式推薦使用默認的bridge網絡模式!
細心一點能夠發現,建立的容器默認狀況IP地址爲172.17.0.0/16網段,那麼咱們可不能夠自定義一個網段供容器使用呢?答案確定是能夠的,方法以下:
[root@localhost ~]# docker network create -d bridge my_net //建立一個橋接網絡,名稱爲my_net,若是沒有指定網段,默認是172.18.0.0/16,按docker0的網段自動遞增 [root@localhost ~]# docker network ls //查看docker支持的網絡類型 NETWORK ID NAME DRIVER SCOPE 9fba9dc3d2b6 bridge bridge local 624b3ba70637 host host local 74544573aa67 my_net bridge local 62f80646f707 none null local //能夠看出,剛纔建立的my_net已經出如今列表中 [root@localhost ~]# docker run -itd --name test1 --network my_net busybox:latest /bin/sh [root@localhost ~]# docker run -itd --name test2 --network my_net busybox:latest /bin/sh //使用剛纔建立的網絡模式建立兩個容器 [root@localhost ~]# docker exec -it test1 /bin/sh //進入test1 / # 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 11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever //查看其IP地址,發現確實是172.18.0.0/16網段的 / # ping test2 //測試經過容器名稱ping test2容器 PING test2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.079 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.175 ms [root@localhost ~]# ifconfig br-74544573aa67 //這張虛擬網卡就是咱們建立my_net網絡時產生的 br-74544573aa67: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::42:50ff:fec2:7657 prefixlen 64 scopeid 0x20<link> ether 02:42:50:c2:76:57 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 //經過IP地址網段就可看出
自定義網絡的優勢:
- 能夠經過容器的名稱進行通訊;
- 自定了ContainerDNSserver功能;
以上方法按照默認的方式建立一個橋接模式的網絡,能夠發現網段地址並非咱們自定義的。
接下來咱們經過指定具體網段的方式建立網卡。方法以下:
[root@localhost ~]# docker network create -d bridge --subnet 200.0.0.0/24 --gateway 200.0.0.1 my_net2 //自定義網絡模式的地址時,必需要明確指定其IP網段及網關信息 [root@localhost ~]# ifconfig br-0ca6770b4a10 //這張虛擬網卡即是咱們建立my_net2網絡時產生的 br-0ca6770b4a10: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 200.0.0.1 netmask 255.255.255.0 broadcast 200.0.0.255 ether 02:42:05:ba:8b:fc 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 //能夠看出其IP地址就是咱們指定的IP地址 [root@localhost ~]# docker run -itd --name test3 --network my_net2 --ip 200.0.0.100 busybox:latest [root@localhost ~]# docker run -itd --name test4 --network my_net2 --ip 200.0.0.200 busybox:latest //基於剛纔建立的網絡建立出兩個容器並指定其固定的IP地址 [root@localhost ~]# docker exec -it test3 /bin/sh //進入test3容器 / # 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 16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c8:00:00:64 brd ff:ff:ff:ff:ff:ff inet 200.0.0.100/24 brd 200.0.0.255 scope global eth0 valid_lft forever preferred_lft forever //發現其IP地址確實咱們剛纔指定的IP地址 / # ping test4 //測試發現確實是能夠和test4通訊的 PING test4 (200.0.0.200): 56 data bytes 64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.156 ms 64 bytes from 200.0.0.200: seq=1 ttl=64 time=0.178 ms / # ping test1 ping: bad address 'test1' //發現沒法與第一次建立的網絡進行通訊
使用相同的網絡建立的容器是能夠相互通訊的,可是發現沒法與其餘容器進行通訊,這主要是由於iptables規則的緣由,建立docker網絡時,iptables規則就會隨着自動添加的。
舉例說:嘗試把iptables規則清空,是能夠實現咱們想要的效果的。可是這種命令的做用不亞於「rm -rf /*」,顯然在現實環境中是不可使用的!
那麼就須要使用下面的方法來實現了,方法以下:
[root@localhost ~]# docker network connect my_net2 test1 //這條命令就是在test1容器中添加一塊虛擬網卡(my_net2分配的) [root@localhost ~]# docker exec -it test1 /bin/sh / # 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 11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever 20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c8:00:00:02 brd ff:ff:ff:ff:ff:ff inet 200.0.0.2/24 brd 200.0.0.255 scope global eth1 valid_lft forever preferred_lft forever //能夠查詢到確實多了一塊虛擬網卡,網段確實和my_net2屬於同一網段 / # ping test3 PING test3 (200.0.0.100): 56 data bytes 64 bytes from 200.0.0.100: seq=0 ttl=64 time=0.171 ms 64 bytes from 200.0.0.100: seq=1 ttl=64 time=0.237 ms ^C --- test3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.171/0.204/0.237 ms / # ping test4 PING test4 (200.0.0.200): 56 data bytes 64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.097 ms ^C --- test4 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.097/0.097/0.097 ms //測試與test三、test4通訊,通訊正常
注意:此時test2容器並不能夠與test三、test4進行通訊!若是須要其通訊,還需給test2添加虛擬my_net2網卡地址(使用案例中的命令便可)!
注意:
- 容器之間可使用容器名進行通訊,但前提必須是使用自定義網絡,好比案例中建立的my_net、my_net2;
- 若是在建立自定義網絡時,指定了該網絡的網段,那麼使用此時的容器也能夠指定容器的IP地址,若沒有指定該網絡的網段,則不可指定容器的IP地址;
本篇博文實現docker跨主機通訊主要是使用consul服務的特性!
consul:是一個服務網格(微服務間的 TCP/IP,負責服務之間的網絡調用、限流、熔斷和監控)解決方案,它是一個一個分佈式的,高度可用的系統,並且開發使用都很簡便。它提供了一個功能齊全的控制平面,主要特色是:服務發現、健康檢查、鍵值存儲、安全服務通訊、多數據中心。
經過一個小案例來驗證consul服務的特性!
(1)關閉防火牆與SELinux(實驗環境);
(2)更改主機名,避免發生衝突;
(1)Docker1
[root@Docker1 ~]# docker pull progrium/consul //下載consul鏡像 [root@Docker1 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart=always progrium/consul -server -bootstrap //-d:後臺運行; //-p:將容器中的8500端口映射到宿主機的8500端口; //-h:表示consul容器的主機名; //--name:表示運行的容器名; //--restart=always:隨docker服務的啓動而啓動; //-server -bootstrap:添加這兩個選項,則表示在羣集環境中可使其以master的身份出現; [root@Docker1 ~]# netstat -anpt | grep 8500 tcp6 0 0 :::8500 :::* LISTEN 2442/docker-proxy //肯定其8500端口正在監聽
(2)Docker2
[root@Docker2 ~]# vim /usr/lib/systemd/system/docker.service //編寫Docker的主配置文件 13 ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 //在第13行上本來的基礎添加以上內容,各個配置項含義以下: # /var/run/docker.sock:Docker的一個套接字; # 「 -H tcp://0.0.0.0:2376 」 :使用本機的tcp2376端口; # 「 --cluster-store=consul://192.168.1.1:8500」:指定運行着consul服務的docker服務器IP及端口; # 「 --cluster-advertise=ens33:2376」:從本機的ens33網卡經過2376端口蒐集網絡信息,存儲在consul上 [root@Docker2 ~]# systemctl daemon-reload [root@Docker2 ~]# systemctl restart docker //從新啓動docker服務
(3)Docker3
Docker3與Docker2的操做就是如出一轍的,因此這裏就很少作解釋了!
[root@Docker3 ~]# vim /usr/lib/systemd/system/docker.service 13 ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 [root@Docker3 ~]# systemctl daemon-reload [root@Docker3 ~]# systemctl restart docker
(4)使用瀏覽器訪問consul服務的web頁面
如圖:
(5)將Docker1服務器也加入到consul羣集
[root@Docker1 ~]# vim /usr/lib/systemd/system/docker.service 13 ExecStart=/usr/bin/dockerd -H unix:////var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 [root@Docker1 ~]# systemctl daemon-reload [root@Docker1 ~]# systemctl restart docker //解釋上面都已經解釋的很清楚,這裏就不作解釋了
再次訪問consul的web頁面,如圖:
若是在此過程當中,訪問web頁面若是出現「500」的錯誤頁面,將運行consul服務的容器刪除從新創新便可!
(6)建立一個 overlay網絡
[root@Docker1 ~]# docker network create -d overlay my_olay //建立一個名爲my_olay的voerlay網絡 //以上操做無論在那臺docker主機上操做均可以 [root@Docker1 ~]# docker network create -d overlay --subnet 200.0.0.0/24 --gateway 200.0.0.1 lv_olay //也能夠在建立overlay網卡時,指定其IP網段及網關 [root@Docker1 ~]# docker network ls //查看docker所支持的網絡
並且在另外兩臺docker服務器上也可看到,自行驗證!
在docker 1上建立的網絡,能夠看到其SPOCE(範圍)定義的是global(全局),那麼這就意味着加入consul這個服務羣集的其餘docker服務器也能夠看到這張網卡!
若是在建立網卡時,沒有指定其網段,則默認是10.0.0.0網段,因爲是自定義網絡,因此知足自定義網絡的特徵(好比支持容器之間的通訊)!
(7)在不一樣的docker服務器各自建立一個容器,驗證是否能夠通訊!
[root@Docker1 ~]# docker run -itd --name t1 --network lv_olay --ip 200.0.0.10 busybox:latest //在docker1服務器上建立一個名爲t1的容器並指定其IP地址 [root@Docker2 ~]# docker run -itd --name t2 --network lv_olay --ip 200.0.0.20 busybox:latest //在docker2上建立一個容器並指定IP地址 [root@Docker3 ~]# docker run -itd --name t3 --network lv_olay --ip 200.0.0.30 busybox:latest //在docker3上建立一個容器並指定IP地址 [root@Docker1 ~]# docker exec -it t1 /bin/sh //隨便在一臺docker服務器上進入其建立的容器中,進行測試
如圖:
(1)手動指定映射端口
[root@localhost ~]# docker run -itd --name web1 -p 90:80 nginx //將一個容器的nginx服務映射到宿主機的90端口
(2)隨機映射端口[root@localhost ~]# docker run -itd --name web2 -p 80 nginx //若是-p以後只有一個端口,則是容器中的端口(宿主機會隨機映射一個端口)從32768端口開始
(3)將容器中的端口所有映射到宿主機上
[root@localhost ~]# docker run -itd --name web4 -P nginx //注意:大寫的P //從宿主機隨機映射端口到容器,容器內全部暴露的端口,都會一一映射
以上操做,我的驗證沒有問題,這裏就不截圖示範了!
—————————本文到此結束,感謝觀看—————————