Docker容器间网络通信

自从Docker容器出现以来,容器网络通信就一直是被关注的焦点,也是生产环境的迫切需求。容器网络通信又分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信。

一、Docker单主机容器通信
基于对net namespace的控制,docker可以为在容器创建隔离的网络环境,在隔离的网络环境下,容器具有完全独立的网络栈,与宿主机隔离,也可以使容器共享主机或者其他容器的网络命名空间,基本可以满足开发者在各种场景下的需要。

按docker官方的说法,docker容器的网络有五种模式:
bridge模式,--net=bridge(默认)
这是dokcer网络的默认设置,为容器创建独立的网络命名空间,容器具有独立的网卡等所有单独的网络栈,是最常用的使用方式。在docker run启动容器的时候,如果不加--net参数,就默认采用这种网络模式。安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过DHCP获取一个与docker0同网段的IP地址,并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。

host模式,--net=host
这个模式下创建出来的容器,直接使用容器宿主机的网络命名空间。将不拥有自己独立的Network Namespace,即没有独立的网络环境。它使用宿主机的ip和端口。

none模式,--net=none
为容器创建独立网络命名空间,但不为它做任何网络配置,容器中只有lo,用户可以在此基础上,对容器网络做任意定制。这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置IP。因此,若想使用pipework配置docker容器的ip地址,必须要在none模式下才可以。

其他容器模式(即container模式,join模式),--net=container:NAME_or_ID
与host模式类似,只是容器将与指定的容器共享网络命名空间。这个模式就是指定一个已有的容器,共享该容器的IP和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。

用户自定义:docker 1.9版本以后新增的特性,允许容器使用第三方的网络实现或者创建单独的bridge网络,提供网络隔离能力。

这些网络模式在相互网络通信方面的对比如下所示:

南北向通信指容器与宿主机外界的访问机制,东西向流量指同一宿主机上,与其他容器相互访问的机制。

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端口: 

1

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

在宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则:

1

# 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的自定义网络:

1

# docker network create bri1

则docker会自动生成如下的iptables规则,保证不同网络上的容器无法互相通信。

1

2

# -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,则可以实现容器的跨主机通信。

二、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集群上实现跨主机网络。典型实现方案有Weave、Flannel的早期版本。
3)基于三层实现SDN网络:基于三层协议和路由,直接在三层上实现跨主机网络,并且通过iptables实现网络的安全隔离。典型的方案为 Calico。同时对不支持三层路由的环境,Calico还提供了基于IPIP封装的跨主机网络实现

Dokcer通过使用Linux桥接提供容器之间的通信,docker0桥接接口的目的就是方便Docker管理。当Docker daemon启动时需要做以下操作:
->  如果docker0不存在则创建
->  搜索一个与当前路由不冲突的ip段
->  在确定的范围中选择 ip
->  绑定ip到 docker0

列出当前主机网桥

1

2

3

[root@localhost ~]# brctl show

bridge name    bridgeid           STP enabled   interfaces

docker0        8000.02426f15541e   no            vethe833b02

查看当前 docker0 ip

1

2

3

4

5

6

7

8

9

10

[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网段的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

[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路由转发功能一定要打开,否则所创建的容器无法联网!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

[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=53time=2.09 ms

64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=2 ttl=53time=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.1、创建容器使用特定范围的IP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

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 linkset dev docker0 down

$sudo brctl delbr docker0

$sudo brctl addbr bridge0

$sudo ip addr add 192.168.5.1/24 dev bridge0

$sudo ip linkset 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   bridgeid           STP enabled     interfaces

bridge0       8000.ba141fa20c91   no              vethe7e227b

                                                  vethf382771

使用pipework给容器设置一个固定的ip

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

可以利用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.2、不同主机间的容器通信(pipework  config docker container ip)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

我的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   bridgeid           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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

一、在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

  

二、在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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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

三、启动容器测试
Server1和Server2上修改docker启动的虚拟网卡绑定为kbr0,重启docker进程
1)在Server1宿主机上启动容器,然后登陆容器内查看ip,就会发现ip是上面设定额172.17.1.0/24网段的

1

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

2)在Server2宿主机上启动容器,然后登陆容器内查看ip,就会发现ip是上面设定额172.17.2.0/24网段的

1

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

然后在上面启动的容内互ping对方容器,发现是可以ping通的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/535313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker容器的重启策略

1. Docker容器的重启策略 Docker容器的重启策略是面向生产环境的一个启动策略&#xff0c;在开发过程中可以忽略该策略。 Docker容器的重启都是由Docker守护进程完成的&#xff0c;因此与守护进程息息相关。 Docker容器的重启策略如下&#xff1a; no&#xff0c;默认策略&…

innobackupex实现导出和导入单张表

默认情况下&#xff0c;InnoDB表不能通过直接复制表文件的方式在mysql服务器之间进行移植&#xff0c;即便使用了innodb_file_per_table选项。而使用Xtrabackup工具可以实现此种功能&#xff0c;不过只能"导出"具有.ibd文件的表&#xff0c;也就是说导出表的mysql服务…

xtrabackup工具

(1).备份过程 和innobackupex备份过程不同的是&#xff0c;xtrabackup的备份路径是由"--target-dir"选项严格指定的&#xff0c;如果指定的目录不存在&#xff0c;它备份的时候不会在target-dir目录中再创建时间戳子目录。 [rootxuexi data]# xtrabackup --backup …

mysql数据库参数

注意&#xff1a;在配置binlog相关变量的时候&#xff0c;相关变量名总是搞混&#xff0c;因为有的是binlog&#xff0c;有的是log_bin&#xff0c;当他们分开的时候&#xff0c;log在前&#xff0c;当它们一起的时候&#xff0c;bin在前。在配置文件中也同样如此。 log_bin …

oracle命令行安装

cd /home/oracle/databases/runInstaller -silent -force -showprogress -responseFile /home/oracle/database/db_install.rsp -ignoreSysPrereqs -ignorePrereqdbca -silent -responseFile pwd/dbca.rspnetca -silent -responseFile /home/oracle/databases/netca.rsp

定期删除数据脚本

#!/bin/sh backup_dir/data/xtrabackup DATEdate %Y-%m-%d #DATE_NOWdate %Y-%m-%d.%H%M DATE_NOWdate %Y-%m-%d PATH/usr/local/mysql/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin export PATH#binog保留7天 binlog/data/binlogserver binlog_Rtime7#备…

定期备份数据库脚本

#!/bin/bash MasterIp* USERroot PORT3306 PASSWD000000 DATEdate %Y-%m-%d #DATE_NOWdate %Y-%m-%d.%H%M DATE_NOWdate %Y-%m-%d OLDDATEdate %Y-%m-%d -d "30 days ago"  #全表备份 BACKUPDIR/data/mysql_backup/fulltable #单表tb_trcevt备份 datapath/data/mysq…

日志清理脚本

#!/bin/bash#定义日志所在分区当前空间所占比例数(去掉%)。grep -w表示精准匹配&#xff0c;只匹配"/"这个分区 LOG_PARTITION$(which df -h|awk {print $5,$6}|grep -w "/"|cut -d" " -f1|awk -F"%" {print $1}) #定义一周前的日期&a…

k8s二进制安装

1. 前言 之前文章安装 kubernetes 集群&#xff0c;都是使用 kubeadm 安装&#xff0c;然鹅很多公司也采用二进制方式搭建集群。这篇文章主要讲解&#xff0c;如何采用二进制包来搭建完整的高可用集群。相比使用 kubeadm 搭建&#xff0c;二进制搭建要繁琐很多&#xff0c;需要…

Logstash mutate 插件

mutate 插件可以在字段上执行变换&#xff0c;包括重命名、删除、替换和修改。这个插件相当常用。 比如&#xff1a; 你已经根据 Grok 表达式将 Tomcat 日志的内容放到各个字段中&#xff0c;想把状态码、字节大小或是响应时间&#xff0c;转换成整型&#xff1b;你已经根据正则…

nginx日志分析脚本

#!/usr/bin/env bashecho "" echo " " echo " \ Nginx日志安全分析脚本 V1.0 / " echo " " echo " # 支持Nginx日志分析&#xff0c;攻击告警分析等 " echo " # auth…

ELK学习笔记之Logstash详解

0x00 Logstash概述 官方介绍&#xff1a;Logstash is an open source data collection engine with real-time pipelining capabilities。简单来说logstash就是一根具备实时数据传输能力的管道&#xff0c;负责将数据信息从管道的输入端传输到管道的输出端&#xff1b;与此同时…

nginx-zabbix监控脚本

nginx_status_fun (){#函数内容NGINX_PORT$1#端口&#xff0c;函数的第一个参数是脚本的第二个参数&#xff0c;即脚本的第二个参数是段端口号NGINX_COMMAND$2#命令&#xff0c;函数的第二个参数是脚本的第三个参数&#xff0c;即脚本的第三个参数是命令nginx_active(){ #获…

percona-xtrabackup备份

#!/bin/bash # 需要安装 percona-xtrabackup # xtrabackup: https://www.percona.com/downloads/Percona-XtraBackup-2.4/LATEST/ # xtrabackup 版本&#xff1a;2.4.24 (RPM安装) # MySQL 版本: 5.7.36 (RPM安装) # version: 22.01.17# 备份服务器 ip DB_BACKUP_SERVER"…

k8---proxy

kube-proxy 通过 Informer知道了Service、endpoints对象的创建&#xff0c;然后把service身上的CLUSTER-IP 和端口已经端点信息拿出来&#xff0c;创建iptable NAT规则做转发或通过ipvs模块创建VS服务器&#xff0c;这样经过CLUSTER-IP的流量都被转发到后端pod。 iptables模式 …

k8s--configmap

当卷中使用的ConfigMap被更新时&#xff0c;所投射的键最终也会被更新。kubelet组件会在每次周期性同步时检查所挂载的ConfigMap是否为最新。 不过,kubelet使用的是其本地的高速缓存来获得ConfigMap的当前值。 ConfigMap既可以通过watch操作实现内容传播&#xff08;默认形式&…

etcd命令

[rootlocalhost calico]# etcdctl get /coreos.com/network/subnets/4.0.32.0-24 {"PublicIP":"10.8.65.53"} 从etcd中查询出4.0.32.0/24的子网的宿主机host的ip10.8.65.53。

docker搭建ldap

1.下载镜像 docker pull osixia/openldap docker pull docker.io/osixia/phpldapadmin 2.运行镜像 docker run -dit --name ldap23 --restartalways -p 389:389 -p 636:636 -e LDAP_ORGANISATION”test” -e LDAP_DOMAIN”test.com” -e LDAP_ADMIN_PASSWORD123456″ osixi…

centos 缩减逻辑卷

在使用期间磁盘空间不足&#xff0c;发现/dev/mapper/centos-home下还有很多空间&#xff0c;如果想要将home下面的磁盘空间分配到root磁盘下面&#xff0c;可以使用以下方法 查看磁盘空间&#xff0c;每个人的磁盘名称可能不同 df -h 1 备份home文件 tar cvf /tmp/home.tar /…

zabbix自动发现监控脚本

自动发现端口列表脚本 # -*- coding: utf-8 -*- import os import json data{} tcp_list[] port_list[] commandos.popen("ss -4tln | awk -F [ :] NR>2{print $5}") for port in command:port_list.append(port.strip()) for port in port_list:port_dict{}por…