Docker容器間網絡通訊的方案 - 運維筆記

 

自從Docker容器出現以來,容器網絡通訊就一直是被關注的焦點,也是生產環境的迫切需求。容器網絡通訊又分爲兩大方面:單主機容器上的相互通訊,和跨主機的容器相互通訊node

1、Docker單主機容器通訊
基於對net namespace的控制,docker能夠爲在容器建立隔離的網絡環境,在隔離的網絡環境下,容器具備徹底獨立的網絡棧,與宿主機隔離,也可使容器共享主機或者其餘容器的網絡命名空間,基本能夠知足開發者在各類場景下的須要。linux

按docker官方的說法,docker容器的網絡有五種模式:
bridge模式,--net=bridge(默認)
這是dokcer網絡的默認設置,爲容器建立獨立的網絡命名空間,容器具備獨立的網卡等全部單獨的網絡棧,是最經常使用的使用方式。在docker run啓動容器的時候,若是不加--net參數,就默認採用這種網絡模式。安裝完docker,系統會自動添加一個供docker使用的網橋docker0,咱們建立一個新的容器時,容器經過DHCP獲取一個與docker0同網段的IP地址,並默認鏈接到docker0網橋,以此實現容器與宿主機的網絡互通。nginx

host模式,--net=host
這個模式下建立出來的容器,直接使用容器宿主機的網絡命名空間。將不擁有本身獨立的Network Namespace,即沒有獨立的網絡環境。它使用宿主機的ip和端口。git

none模式,--net=none
爲容器建立獨立網絡命名空間,但不爲它作任何網絡配置,容器中只有lo,用戶能夠在此基礎上,對容器網絡作任意定製。這個模式下,dokcer不爲容器進行任何網絡配置。須要咱們本身爲容器添加網卡,配置IP。所以,若想使用pipework配置docker容器的ip地址,必需要在none模式下才能夠。github

其餘容器模式(即container模式,join模式),--net=container:NAME_or_ID
與host模式相似,只是容器將與指定的容器共享網絡命名空間。這個模式就是指定一個已有的容器,共享該容器的IP和端口。除了網絡方面兩個容器共享,其餘的如文件系統,進程等仍是隔離開的。docker

用戶自定義:docker 1.9版本之後新增的特性,容許容器使用第三方的網絡實現或者建立單獨的bridge網絡,提供網絡隔離能力。ubuntu

這些網絡模式在相互網絡通訊方面的對好比下所示:vim

南北向通訊指容器與宿主機外界的訪問機制,東西向流量指同一宿主機上,與其餘容器相互訪問的機制。centos

1)host模式
因爲容器和宿主機共享同一個網絡命名空間,換言之,容器的IP地址即爲宿主機的IP地址。因此容器能夠和宿主機同樣,使用宿主機的任意網卡,實現和外界的通訊。其網絡模型能夠參照下圖:安全

採用host模式的容器,能夠直接使用宿主機的IP地址與外界進行通訊,若宿主機具備公有IP,那麼容器也擁有這個公有IP。同時容器內服務的端口也可使用宿主機的端口,無需額外進行NAT轉換,並且因爲容器通訊時,再也不須要經過linuxbridge等方式轉發或數據包的拆封,性能上有很大優點。固然,這種模式有優點,也就有劣勢,主要包括如下幾個方面:
1)最明顯的就是容器再也不擁有隔離、獨立的網絡棧。容器會與宿主機競爭網絡棧的使用,而且容器的崩潰就可能致使宿主機崩潰,在生產環境中,這種問題多是不被容許的。
2)容器內部將再也不擁有全部的端口資源,由於一些端口已經被宿主機服務、bridge模式的容器端口綁定等其餘服務佔用掉了。

2)bridge模式
bridge模式是docker默認的,也是開發者最常使用的網絡模式。在這種模式下,docker爲容器建立獨立的網絡棧,保證容器內的進程使用獨立的網絡環境,實現容器之間、容器與宿主機之間的網絡棧隔離。同時,經過宿主機上的docker0網橋,容器能夠與宿主機乃至外界進行網絡通訊。其網絡模型能夠參考下圖:

從上面的網絡模型能夠看出,容器從原理上是能夠與宿主機乃至外界的其餘機器通訊的。同一宿主機上,容器之間都是鏈接掉docker0這個網橋上的,它能夠做爲虛擬交換機使容器能夠相互通訊。然而,因爲宿主機的IP地址與容器veth pair的 IP地址均不在同一個網段,故僅僅依靠veth pair和namespace的技術,還不足以使宿主機之外的網絡主動發現容器的存在。爲了使外界能夠方位容器中的進程,docker採用了端口綁定的方式,也就是經過iptables的NAT,將宿主機上的端口端口流量轉發到容器內的端口上。舉一個簡單的例子,使用下面的命令建立容器,並將宿主機的3306端口綁定到容器的3306端口: 

# docker run -tid --name db -p 3306:3306 MySQL

在宿主機上,能夠經過iptables -t nat -L -n,查到一條DNAT規則:

# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306

上面的172.17.0.5即爲bridge模式下,建立的容器IP。

很明顯,bridge模式的容器與外界通訊時,一定會佔用宿主機上的端口,從而與宿主機競爭端口資源,對宿主機端口的管理會是一個比較大的問題。同時,因爲容器與外界通訊是基於三層上iptables NAT,性能和效率上的損耗是能夠預見的。

3)none模式
在這種模式下,容器有獨立的網絡棧,但不包含任何網絡配置,只具備lo這個loopback網卡用於進程通訊。也就是說,none模式爲容器作了最少的網絡設置,可是俗話說得好「少便是多」,在沒有網絡配置的狀況下,經過第三方工具或者手工的方式,開發這任意定製容器的網絡,提供了最高的靈活性。

4)其餘容器(container)模式
其餘網絡模式是docker中一種較爲特別的網絡的模式。在這個模式下的容器,會使用其餘容器的網絡命名空間,其網絡隔離性會處於bridge橋接模式與host模式之間。當容器共享其餘容器的網絡命名空間,則在這兩個容器之間不存在網絡隔離,而她們又與宿主機以及除此以外其餘的容器存在網絡隔離。其網絡模型能夠參考下圖:

在這種模式下的容器能夠經過localhost來同一網絡命名空間下的其餘容器,傳輸效率較高。並且這種模式還節約了必定數量的網絡資源,但它並無改變容器與外界通訊的方式。在一些特殊的場景中很是有用,例如,kubernetes的pod,kubernetes爲pod建立一個基礎設施容器,同一pod下的其餘容器都以其餘容器模式共享這個基礎設施容器的網絡命名空間,相互之間以localhost訪問,構成一個統一的總體。

5)用戶定義網絡模式
在用戶定義網絡模式下,開發者可使用任何docker支持的第三方網絡driver來定製容器的網絡。而且,docker 1.9以上的版本默認自帶了bridge和overlay兩種類型的自定義網絡driver。能夠用於集成calico、weave、openvswitch等第三方廠商的網絡實現。 除了docker自帶的bridge driver,其餘的幾種driver均可以實現容器的跨主機通訊。而基於bdrige driver的網絡,docker會自動爲其建立iptables規則,保證與其餘網絡之間、與docker0之間的網絡隔離。 例如,使用下面的命令建立一個基於bridge driver的自定義網絡:

# docker network create bri1

則docker會自動生成以下的iptables規則,保證不一樣網絡上的容器沒法互相通訊。

# -A DOCKER-ISOLATION -i br-8dba6df70456 -o docker0 -j DROP 
# -A DOCKER-ISOLATION -i docker0 -o br-8dba6df70456 -j DROP

除此以外,bridge driver的全部行爲都和默認的bridge模式徹底一致。而overlay及其餘driver,則能夠實現容器的跨主機通訊。

2、Docker跨主機容器通訊

早期你們的跨主機通訊方案主要有如下幾種:
1)容器使用host模式:容器直接使用宿主機的網絡,這樣天生就能夠支持跨主機通訊。雖然能夠解決跨主機通訊問題,但這種方式應用場景頗有限,容易出現端口衝突,也沒法作到隔離網絡環境,一個容器崩潰極可能引發整個宿主機的崩潰。

2)端口綁定:經過綁定容器端口到宿主機端口,跨主機通訊時,使用主機IP+端口的方式訪問容器中的服務。顯而易見,這種方式僅能支持網絡棧的四層及以上的應用,而且容器與宿主機緊耦合,很難靈活的處理,可擴展性不佳。

3)docker外定製容器網絡:在容器經過docker建立完成後,而後再經過修改容器的網絡命名空間來定義容器網絡。典型的就是好久之前的pipework,容器以none模式建立,pipework經過進入容器的網絡命名空間爲容器從新配置網絡,這樣容器網絡能夠是靜態IP、vxlan網絡等各類方式,很是靈活,容器啓動的一段時間內會沒有IP,明顯沒法在大規模場景下使用,只能在實驗室中測試使用。

4)第三方SDN定義容器網絡:使用Open vSwitch或Flannel等第三方SDN工具,爲容器構建能夠跨主機通訊的網絡環境。這些方案通常要求各個主機上的docker0網橋的cidr不一樣,以免出現IP衝突的問題,限制了容器在宿主機上的可獲取IP範圍。而且在容器須要對集羣外提供服務時,須要比較複雜的配置,對部署實施人員的網絡技能要求比較高。

上面這些方案有各類各樣的缺陷,同時也由於跨主機通訊的迫切需求,docker 1.9版本時,官方提出了基於vxlan的overlay網絡實現,原生支持容器的跨主機通訊。同時,還支持經過libnetwork的plugin機制擴展各類第三方實現,從而以不一樣的方式實現跨主機通訊。目前社區比較流行的方案來講,跨主機通訊的基本實現方案有如下幾種:

1)基於隧道的overlay網絡:按隧道類型來講,不一樣的公司或者組織有不一樣的實現方案。docker原生的overlay網絡就是基於vxlan隧道實現的。ovn則須要經過geneve或者stt隧道來實現的。flannel最新版本也開始默認基於vxlan實現overlay網絡。
2)基於包封裝的overlay網絡:基於UDP封裝等數據包包裝方式,在docker集羣上實現跨主機網絡。典型實現方案有WeaveFlannel的早期版本。
3)基於三層實現SDN網絡:基於三層協議和路由,直接在三層上實現跨主機網絡,而且經過iptables實現網絡的安全隔離。典型的方案爲 Calico。同時對不支持三層路由的環境,Calico還提供了基於IPIP封裝的跨主機網絡實現

Dokcer經過使用Linux橋接提供容器之間的通訊,docker0橋接接口的目的就是方便Docker管理。當Docker daemon啓動時須要作如下操做:
->  若是docker0不存在則建立
->  搜索一個與當前路由不衝突的ip段
->  在肯定的範圍中選擇 ip
->  綁定ip到 docker0

列出當前主機網橋

[root@localhost ~]# brctl show
bridge name    bridge id           STP enabled   interfaces
docker0        8000.02426f15541e   no            vethe833b02

查看當前 docker0 ip

[root@localhost ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:6fff:fe15:541e  prefixlen 64  scopeid 0x20<link>
        ether 02:42:6f:15:54:1e  txqueuelen 0  (Ethernet)
        RX packets 120315  bytes 828868638 (790.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 132565  bytes 100884398 (96.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
................

在容器運行時,每一個容器都會分配一個特定的虛擬機口並橋接到docker0。每一個容器都會配置同docker0 ip相同網段的專用ip 地址,docker0的IP地址被用於全部容器的默認網關。
通常啓動的容器中ip默認是172.17.0.1/24網段的。

[root@linux-node2 ~]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
centos                       latest              67591570dd29        3 months ago        191.8 MB

[root@linux-node2 ~]# docker run -t -i --name my-test centos /bin/bash
[root@c5217f7bd44c /]# 

[root@linux-node2 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
c5217f7bd44c        centos              "/bin/bash"         10 seconds ago      Up 10 seconds                                my-test
[root@linux-node2 ~]# docker inspect c5217f7bd44c|grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",

那麼能不能在建立容器的時候指定特定的ip呢?這是固然能夠實現的!

注意:宿主機的ip路由轉發功能必定要打開,不然所建立的容器沒法聯網!

[root@localhost ~]# cat /proc/sys/net/ipv4/ip_forward
1
[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6e64eade06d1        docker.io/centos    "/bin/bash"         10 seconds ago      Up 9 seconds                            my-centos
[root@localhost ~]# docker run -itd --net=none --name=container1 docker.io/centos
5e5bdbc4d9977e6bcfa40e0a9c3be10806323c9bf5a60569775903d345869b09
[root@localhost ~]# docker attach container1
[root@5e5bdbc4d997 /]# ping www.baidu.com
PING www.a.shifen.com (61.135.169.121) 56(84) bytes of data.
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=1 ttl=53 time=2.09 ms
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=2 ttl=53 time=2.09 ms

關閉ip路由轉發功能,容器即不能聯網
[root@localhost ~]# echo 0 > /proc/sys/net/ipv4/ip_forward
[root@localhost ~]# cat /proc/sys/net/ipv4/ip_forward
0
[root@5e5bdbc4d997 /]# ping www.baidu.com        //ping不通~

2.一、建立容器使用特定範圍的IP

Docker 會嘗試尋找沒有被主機使用的ip段,儘管它適用於大多數狀況下,可是它不是萬能的,有時候咱們仍是須要對ip進一步規劃。
Docker容許你管理docker0橋接或者經過-b選項自定義橋接網卡,須要安裝bridge-utils軟件包。操做流程以下:
a)確保docker的進程是中止的
b)建立自定義網橋
c)給網橋分配特定的ip
d)以-b的方式指定網橋
 
具體操做過程以下(好比建立容器的時候,指定ip爲192.168.5.1/24網段的):
[root@localhost ~]# service docker stop
[root@localhost ~]# ip link set dev docker0 down
[root@localhost ~]# brctl delbr docker0
[root@localhost ~]# brctl addbr bridge0
[root@localhost ~]# ip addr add 192.168.5.1/24 dev bridge0      //注意,這個192.168.5.1就是所建容器的網關地址。經過docker inspect container_id能查看到
[root@localhost ~]# ip link set dev bridge0 up
[root@localhost ~]# ip addr show bridge0
[root@localhost ~]# vim /etc/sysconfig/docker      //即將虛擬的橋接口由默認的docker0改成bridge0
將
OPTIONS='--selinux-enabled --log-driver=journald'
改成
OPTIONS='--selinux-enabled --log-driver=journald -b=bridge0'    //即添加-b=bridge0
 
[root@localhost ~]# service docker restart
 
--------------------------------------------------------------------------------------
上面是centos7下的操做步驟,下面提供下ubuntu下的操做步驟:
$ sudo service docker stop
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up
$ ip addr show bridge0
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
$ sudo service docker start
--------------------------------------------------------------------------------------
 
而後建立容器,查看下容器ip是否爲設定的192.168.5.1/24網段的
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/ubuntu    latest              0ef2e08ed3fa        2 weeks ago         130 MB
centos7             7.3.1611            d5ebea14da54        3 weeks ago         311 MB
 
[root@localhost ~]# docker run -t -i --name test2 centos7:7.3.1611 /bin/bash
[root@224facf8e054 /]#
 
[root@localhost ~]# docker run -t -i --name test1 docker.io/ubuntu /bin/bash
root@f5b1bfc2811a:/#
 
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
224facf8e054        centos7:7.3.1611    "/bin/bash"         46 minutes ago      Up 46 minutes                           test2
f5b1bfc2811a        docker.io/ubuntu    "/bin/bash"         47 minutes ago      Up 5 minutes                            test1
[root@localhost ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' f5b1bfc2811a
192.168.5.2
[root@localhost ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' 224facf8e054
192.168.5.3

[root@localhost ~]# brctl show
bridge name   bridge id           STP enabled     interfaces
bridge0       8000.ba141fa20c91   no              vethe7e227b
                                                  vethf382771

使用pipework給容器設置一個固定的ip

能夠利用pipework爲容器指定一個固定的ip,操做方法很是簡單,以下:
[root@node1 ~]# brctl addbr br0
[root@node1 ~]# ip link set dev br0 up
[root@node1 ~]# ip addr add 192.168.114.1/24 dev br0                        //這個ip至關於br0網橋的網關ip,能夠隨意設定。
[root@node1 ~]# docker run -ti -d --net=none --name=my-test1 docker.io/nginx /bin/bash
[root@node1 ~]# pipework br0 -i eth0 my-test1 192.168.114.100/24@192.168.114.1

[root@node1 ~]# docker exec -ti my-test1 /bin/bash
root@cf370a090f63:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    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
57: eth0@if58: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b2:c1:8d:92:33:e2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.114.100/24 brd 192.168.114.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::b0c1:8dff:fe92:33e2/64 scope link 
       valid_lft forever preferred_lft forever


再啓動一個容器
[root@node1 ~]# docker run -ti -d --net=none --name=my-test2 docker.io/nginx /bin/bash
[root@node1 ~]# pipework br0 -i eth0 my-test12 192.168.114.200/24@192.168.114.1
[root@node1 ~]# pipework br0 -i eth0 my-test2 192.168.114.200/24@192.168.114.1

這樣,my-test1容器和my-test2容器在同一個宿主機上,因此它們固定後的ip是能夠相互ping通的,若是是在不一樣的宿主機上,則就沒法ping通!

因此說:
這樣使用pipework指定固定ip的容器,在同一個宿主機下的容器間的ip是能夠相互ping通的,可是跨主機的容器經過這種方式固定ip後就不能ping通了。
跨主機的容器間的通訊能夠看下面的介紹。

2.二、不一樣主機間的容器通訊(pipework  config docker container ip)

個人centos7測試機上的docker是yum安裝的,默認自帶pipework工具,因此就不用在另行安裝它了。
-----------------------------------------------------------------------------------------------
若是沒有pipework工具,能夠安裝下面步驟進行安裝:
# git clone https://github.com/jpetazzo/pipework.git
# sudo cp -rp pipework/pipework /usr/local/bin/
     
安裝相應依賴軟件(網橋)
#sudo apt-get install iputils-arping bridge-utils -y
-----------------------------------------------------------------------------------------------
    
查看Docker宿主機上的橋接網絡
[root@linux-node2 ~]# brctl show
bridge name   bridge id           STP enabled   interfaces
docker0       8000.02426f15541e   no            veth92d132f
   
有兩種方式作法:
1)能夠選擇刪除docker0,直接把docker的橋接指定爲br0;
2)也能夠選擇保留使用默認docker0的配置,這樣單主機容器之間的通訊能夠經過docker0;
   跨主機不一樣容器之間經過pipework將容器的網卡橋接到br0上,這樣跨主機容器之間就能夠通訊了。
   
若是保留了docker0,則容器啓動時不加--net=none參數,那麼本機容器啓動後就是默認的docker0自動分配的ip(默認是172.17.1.0/24網段),它們之間是能夠通訊的;
跨宿主機的容器建立時要加--net=none參數,待容器啓動後經過pipework給容器指定ip,這樣跨宿主機的容器ip是在同一網段內的同網段地址,所以能夠通訊。
  
通常來講:最好在建立容器的時候加上--net=none,防止自動分配的IP在局域網中有衝突。如果容器建立後自動獲取ip,下次容器啓動會ip有變化,可能會和物理網段中的ip衝突
 
---------------------------------------------------------------------------------------------------
實例說明以下:
宿主機信息
ip:192.168.1.23          (網卡設備爲eth0)
gateway:192.168.1.1
netmask:255.255.255.0

1)刪除虛擬橋接卡docker0的配置
[root@localhost ~]# service docker stop
[root@localhost ~]# ip link set dev docker0 down 
[root@localhost ~]# brctl delbr docker0
[root@localhost ~]# brctl addbr br0
[root@localhost ~]# ip link set dev br0 up       
[root@localhost ~]# ip addr del 192.168.1.23/24 dev eth0       //刪除宿主機網卡的IP(若是是使用這個地址進行的遠程鏈接,這一步操做後就會斷掉;若是是使用外網地址鏈接的話,就不會斷開)
[root@localhost ~]# ip addr add 192.168.1.23/24 dev br0        //將宿主主機的ip設置到br0
[root@localhost ~]# brctl addif br0 eth0                        //將宿主機網卡掛到br0上
[root@localhost ~]# ip route del default                       //刪除默認的原路由,其實就是eth0上使用的原路由192.168.1.1(這步當心,注意刪除後要保證機器能遠程鏈接上,最好是經過外網ip遠程連的。別刪除路由後,遠程鏈接不上,中斷了)
[root@localhost ~]# ip route add default via 192.168.1.1 dev br0      //爲br0設置路由
[root@localhost ~]# vim /etc/sysconfig/docker                 //即將虛擬的橋接口由默認的docker0改成bridge0
將
OPTIONS='--selinux-enabled --log-driver=journald'
改成
OPTIONS='--selinux-enabled --log-driver=journald -b=br0'    //即添加-b=br0
  
[root@localhost ~]# service docker start
 
 
啓動一個手動設置網絡的容器
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6e64eade06d1        docker.io/centos    "/bin/bash"         10 seconds ago      Up 9 seconds                            my-centos
[root@localhost ~]# docker run -itd --net=none --name=my-test1 docker.io/centos
  
爲my-test1容器設置一個與橋接物理網絡同地址段的ip(以下,"ip@gateway")
默認不指定網卡設備名,則默認添加爲eth0。能夠經過-i參數添加網卡設備名
[root@localhost ~]# pipework br0 -i eth0 my-test1 192.168.1.190/24@192.168.1.1
 
同理,在其餘機器上啓動容器,並相似上面用pipework設置一個同網段類的ip,這樣跨主機的容器就能夠相互ping通了!
 
--------------------------------------------------------------------------------------------------
2)保留默認虛擬橋接卡docker0的配置
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
[root@localhost network-scripts]# cp ifcfg-eth0 ifcfg-eth0.bak
[root@localhost network-scripts]# cp ifcfg-eth0 ifcfg-br0
[root@localhost network-scripts]# vim ifcfg-eth0            //增長BRIDGE=br0,刪除IPADDR,NETMASK,GATEWAY,DNS的設置
......
BRIDGE=br0
[root@localhost network-scripts]# vim ifcfg-br0            //修改DEVICE爲br0,Type爲Bridge,把eth0的網絡設置設置到這裏來(裏面應該有ip,網關,子網掩碼或DNS設置)
......
TYPE=Bridge
DEVICE=br0
    
[root@localhost network-scripts]# service network restart
    
[root@localhost network-scripts]# service docker restart
    
開啓一個容器並指定網絡模式爲none(這樣,建立的容器就不會經過docker0自動分配ip了,而是根據pipework工具自定ip指定)
[root@localhost network-scripts]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/centos    latest              67591570dd29        3 months ago        191.8 MB
[root@localhost network-scripts]# docker run -itd --net=none --name=my-centos docker.io/centos /bin/bash
6e64eade06d1eb20be3bd22ece2f79174cd033b59182933f7bbbb502bef9cb0f
 
接着給容器配置網絡
[root@localhost network-scripts]# pipework br0 -i eth0 my-centos 192.168.1.150/24@192.168.1.1
[root@localhost network-scripts]# docker attach 6e64eade06d1
[root@6e64eade06d1 /]# ifconfig eth0                 //若沒有ifconfig命令,能夠yum安裝net-tools工具
eth0      Link encap:Ethernet  HWaddr 86:b6:6b:e8:2e:4d
          inet addr:192.168.1.150  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::84b6:6bff:fee8:2e4d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:648 (648.0 B)  TX bytes:690 (690.0 B)

[root@6e64eade06d1 /]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.115.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
    
另外pipework不能添加靜態路由,若是有需求則能夠在run的時候加上--privileged=true 權限在容器中手動添加,但這種方法安全性有缺陷。
除此以外,能夠經過ip netns(--help參考幫助)添加靜態路由,以免建立容器使用--privileged=true選項形成一些沒必要要的安全問題:
    
以下獲取指定容器的pid
[root@localhost network-scripts]# docker inspect --format="{{ .State.Pid }}" 6e64eade06d1
7852
[root@localhost network-scripts]# ln -s /proc/7852/ns/net /var/run/netns/7852
[root@localhost network-scripts]# ip netns exec 7852 ip route add 192.168.0.0/16 dev eth0 via 192.168.1.1
[root@localhost network-scripts]# ip netns exec 7852 ip route    //添加成功
192.168.0.0/16 via 192.168.1.1 dev eth0
    
同理,在其它宿主機進行相應的配置,新建容器並使用pipework添加虛擬網卡橋接到br0,如此建立的容器間就能夠相互通訊了。

                                                                                                                                                                               

1)重啓網卡報錯以下:
# systemctl restart network
......
Nov 23 22:09:08 hdcoe02 systemd[1]: network.service: control process exited, code=exited status=1  
Nov 23 22:09:08 hdcoe02 systemd[1]: Failed to start LSB: Bring up/down networking.  
Nov 23 22:09:08 hdcoe02 systemd[1]: Unit network.service entered failed state.</span>  

解決辦法:
# systemctl enable NetworkManager-wait-online.service
# systemctl stop NetworkManager
# systemctl  restart network.service

2)建立容器,出現下面告警
WARNING: IPv4 forwarding is disabled. Networking will not work.
解決辦法:
#vim /usr/lib/sysctl.d/00-system.conf
添加以下代碼:
net.ipv4.ip_forward=1

重啓network服務
# systemctl restart network

                                                                                                                                                                                                   
其實除了上面使用的pipework工具還,還可使用虛擬交換機(Open vSwitch)進行docker容器間的網絡通訊,廢話很少說,下面說下Open vSwitch的使用:

1、在Server1和Server2上分別安裝open vswitch
[root@Slave1 ~]# # yum -y install wget openssl-devel kernel-devel
[root@Slave1 ~]# yum groupinstall "Development Tools"
[root@Slave1 ~]# adduser ovswitch
[root@Slave1 ~]# su - ovswitch
[ovswitch@Slave1 ~]$ wget http://openvswitch.org/releases/openvswitch-2.3.0.tar.gz
[ovswitch@Slave1 ~]$ tar -zxvpf openvswitch-2.3.0.tar.gz
[ovswitch@Slave1 ~]$ mkdir -p ~/rpmbuild/SOURCES
[ovswitch@Slave1 ~]$ sed 's/openvswitch-kmod, //g' openvswitch-2.3.0/rhel/openvswitch.spec > openvswitch-2.3.0/rhel/openvswitch_no_kmod.spec
[ovswitch@Slave1 ~]$ cp openvswitch-2.3.0.tar.gz rpmbuild/SOURCES/
[ovswitch@Slave1 ~]$ rpmbuild -bb --without check ~/openvswitch-2.3.0/rhel/openvswitch_no_kmod.spec
[root@Slave1 ~]$ exit
   
[root@Slave1 ~]# yum localinstall /home/ovswitch/rpmbuild/RPMS/x86_64/openvswitch-2.3.0-1.x86_64.rpm
[root@Slave1 ~]# mkdir /etc/openvswitch
[root@Slave1 ~]# setenforce 0
[root@Slave1 ~]# systemctl start openvswitch.service
[root@Slave1 ~]# systemctl  status openvswitch.service -l
 
2、在Slave1和Slave2上創建OVS Bridge並配置路由
1)在Slave1宿主機上設置docker容器內網ip網段172.17.1.0/24
[root@Slave1 ~]# vim /proc/sys/net/ipv4/ip_forward
1
[root@Slave1 ~]# ovs-vsctl add-br obr0
[root@Slave1 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.115.5
   
[root@Slave1 ~]# brctl addbr kbr0
[root@Slave1 ~]# brctl addif kbr0 obr0
[root@Slave1 ~]# ip link set dev docker0 down
[root@Slave1 ~]# ip link del dev docker0
   
[root@Slave1 ~]# vim /etc/sysconfig/network-scripts/ifcfg-kbr0
ONBOOT=yes
BOOTPROTO=static
IPADDR=172.17.1.1
NETMASK=255.255.255.0
GATEWAY=172.17.1.0
USERCTL=no
TYPE=Bridge
IPV6INIT=no
   
[root@Slave1 ~]# vim /etc/sysconfig/network-scripts/route-ens32
172.17.2.0/24 via 192.168.115.6 dev ens32
 
[root@Slave1 ~]# systemctl  restart network.service

 

2)在Slave2宿主機上設置docker容器內網ip網段172.17.2.0/24
[root@Slave2 ~]# vim /proc/sys/net/ipv4/ip_forward 
1
[root@Slave2 ~]# ovs-vsctl add-br obr0
[root@Slave2 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.115.6
  
[root@Slave2 ~]# brctl addbr kbr0
[root@Slave2 ~]# brctl addif kbr0 obr0
[root@Slave2 ~]# ip link set dev docker0 down
[root@Slave2 ~]# ip link del dev docker0
  
[root@Slave2 ~] vim /etc/sysconfig/network-scripts/ifcfg-kbr0
ONBOOT=yes
BOOTPROTO=static
IPADDR=172.17.2.1
NETMASK=255.255.255.0
GATEWAY=172.17.2.0
USERCTL=no
TYPE=Bridge
IPV6INIT=no
  
[root@Slave2 ~]# vim /etc/sysconfig/network-scripts/route-ens32 
172.17.1.0/24 via 192.168.115.5 dev ens32
  
[root@Slave2 ~]# systemctl  restart network.service

3、啓動容器測試
Server1和Server2上修改docker啓動的虛擬網卡綁定爲kbr0,重啓docker進程
1)在Server1宿主機上啓動容器,而後登錄容器內查看ip,就會發現ip是上面設定額172.17.1.0/24網段的

[root@Slave1 ~]# docker run -idt --name my-server1 daocloud.io/library/centos/bin/bash

2)在Server2宿主機上啓動容器,而後登錄容器內查看ip,就會發現ip是上面設定額172.17.2.0/24網段的

[root@Slave2 ~]#docker run -idt --name my-server1 daocloud.io/library/centos /bin/bash

而後在上面啓動的容內互ping對方容器,發現是能夠ping通的

相關文章
相關標籤/搜索