一 。同主机容器互连

 1》网络模式简介

同一宿主机的网络模型分为四种模式
  》》Bridge模式

    当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。
bridge模式如下图所示:  


创建容器

[root@cdh2 ~]# docker run -tid --net=bridge --name c1 centos
5958da9979269f1a7f4bfdb5c2ce9169e530445efa330a0e3e54deb9bb3db261
[root@cdh2 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
5958da997926        centos              "/bin/bash"         8 seconds ago       Up 7 seconds                            c1
查看宿主机自动 生成veth docker0的网桥ip是 172.17.0.1
[root@cdh2 ~]# ip addr
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:42:c1:eb:b7 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:42ff:fec1:ebb7/64 scope link 
       valid_lft forever preferred_lft forever
45: vetha4a973c@if44: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP 
    link/ether 02:5e:3f:c8:aa:c0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::5e:3fff:fec8:aac0/64 scope link 
       valid_lft forever preferred_lft forever
查看ip地址(docker inspect查询的json格式可以用 {{.根节点.子节点.....}}获取对应值) 或者直接用 docker inspect c1 | grep IP
[root@cdh2 ~]# docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' c1
/c1 - 172.17.0.2
进入shell命令 安装net-tools
[root@cdh2 ~]# docker exec -it c1 /bin/bash                                      
[root@0441ad51a806 /]# yum -y install net-tools
查看ip地址和网关地址(应该是网桥的ip 172.17.0.1)
[root@0441ad51a806 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 2336  bytes 9346632 (8.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1716  bytes 96631 (94.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
网关(所有ip 走的网关是 172.17.0.1)
[root@0441ad51a806 /]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

桥接方式默认的网关是172.17.0.1 可以通过编辑/etc/docker/daemon.json文件,

添加内容 "bip": "ip/netmask" [ 切勿与宿主机同网段 ] 比如

[root@localhost /]# vi /etc/docker/daemon.json  
{"bip":"192.168.55.1/24"}

网桥方式容器的ip是自动分配的 每次启动容器都会重新分配ip地址 可以修改为 link模式 设置主机名方式

使用link方式进行通信
docker的link机制可以通过一个name(主机名)来和另一个容器通信,link机制方便了容器去发现其它的容器并且可以安全的传递一些连接信息给其它的容器(环境变量)

   启动第一个nginx容器

[root@cdh2 ~]# docker run --name n1 -d -e MYID=1 nginx
   启动第二个nginx容器 并且link了n1 给n1取一个主机名myn1
root@cdh2 ~]# docker run --name n2 -d --link n1:myn1 nginx 
5d1e40750b78e8546723f60ad589da6f1a76b37ee1f70319b087066b9223e608
此时n2容器链接了n1 进入n2容器 查看所有环境变量
[root@cdh2 ~]# docker exec -it n2 /bin/bash
root@5d1e40750b78:/# env                                                                                                                                                                                                                   
MYN1_ENV_NJS_VERSION=1.13.3.0.1.11-1~stretch
MYN1_ENV_NGINX_VERSION=1.13.3-1~stretch
MYN1_PORT_80_TCP_ADDR=172.17.0.2
HOSTNAME=5d1e40750b78
NJS_VERSION=1.13.3.0.1.11-1~stretch
NGINX_VERSION=1.13.3-1~stretch
MYN1_PORT_80_TCP_PORT=80
MYN1_ENV_MYID=1
PWD=/
HOME=/root
MYN1_NAME=/n2/myn1
SHLVL=1
MYN1_PORT=tcp://172.17.0.2:80
MYN1_PORT_80_TCP_PROTO=tcp
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYN1_PORT_80_TCP=tcp://172.17.0.2:80
_=/usr/bin/env
发现n1设置的环境变量 MYID出现在了n2的环境变量中命令 主机名_ENV_变量名
上面的变量被分成了五个部分:
  • 第一个部分是web容器自身提供的一些环境变量,如NGINX_VERSION,HOSTNAME,HOME,PATH等.
  • 第二个部分则是MYN1_ENV开头的变量,这些都是从source container中导入的,变量来源于Dockerfile中使用ENV命令定义的变量,或者是docker run的时候通过-e 添加的环境变量。
  • 第三个部分是MYN1_NAME 这个变量,这变量记录了link的两个容器的组合,这里就是/web/db
  • 第四个部分就是MYN1_PORT开头的一系列变量,这些变量会有很组,每组变量的命名格式如下
<alias>_PORT_<port>_<protocol>
<alias>_PORT_<port>_<protocol>_PORT
<alias>_PORT_<port>_<protocol>_PROTO
<alias>_PORT_<port>_<protocol>_ADDR
其中<port>是在Dockerfile中使用EXPOSE导出的端口,还有docker run 的时候使用-p导出的端口。<protocol>则是这些端口对应的协议。

  • 第五个部分就是MYN1_PORT这个变量,这个变量是EXPOSE导出端口中的第一个端口对应的连接url, 如果有EXPOSE导出的端口,还有docker run -p指定导出的端口,那么通过-p指定的端口是第一个被导出的端口
在容器n2中 可以使用myn1来直接访问 n1这台主机了 每次启动主机 docker自动将myn1对应到n2的ip地址 我们只需要关注这个hostname即可

  》》Host模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

创建 host模式容器查看ip和路由发现和宿主机是一模一样

#docker run -tid --net=host --name c2 centos
#docker exec -it c2 /bin/bash
进入后发现主机名都和宿主机一样
[root@cdh2 ~]# docker exec -it c2 /bin/bash
[root@cdh2 /]# ip adr
使用ifconfig和route -n也是一样 
  》》 Containner模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
Container模式示意图:


尝试将新创建的容器c3 绑定到 c1的网络上 共享网络 ip地址应该都是相同

[root@cdh2 ~]# docker run -tid --net=container:c1 --name=c3 centos
a01bd6386e89d62ebc807fbff0a30f09f9f4ac864a3eb04a259938930e71ee1c
[root@cdh2 ~]# docker exec -it c3 /bin/bash
[root@0441ad51a806 /]# yum -y install net-tools
[root@0441ad51a806 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 6118  bytes 18457579 (17.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4210  bytes 234903 (229.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@0441ad51a806 /]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
 》》 NONE模式
     使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

 

[root@cdh2 ~]# docker run -tid --net=none --name=c3 centos

二。跨主机容器互连

 1》端口映射

  宿主机可以将容器对应局域网的访问nat出去实现访问外部网络 但是外部网络主机无法访问容器资源  可以在宿主机上开启端口

如果来自外部对该端口的访问 docker通过代理自动路由到绑定的容器端口  比如:

容器启动nginx 获取ip地址

[root@cdh2 ~]# docker inspect n1 | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
此时宿主机ip地址是(58.144):
2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:90:75:c5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.58.144/24 brd 192.168.58.255 scope global dynamic eno16777736
       valid_lft 1421sec preferred_lft 1421sec
    inet6 fe80::20c:29ff:fe90:75c5/64 scope link 
       valid_lft forever preferred_lft forever
通过另外一个局域网主机 (58.1) 来直接访问172.17.0.2 是无法访问的
C:\Users\jiaozi>ping 172.17.0.2
正在 Ping 172.17.0.2 具有 32 字节的数据:

58.1仅仅可以访问宿主机 58.144 只能在58.144启动容器是绑定一个端口到容器

docker run --name n3 -p 80:80 -d nginx
通过58.1浏览器访问 发现

2》直接路由

  通过在Docker宿主机上添加静态路由实现跨宿主机通信
 模拟环境 主机1(192.168.58.144) 设置docker0 网关 (172.17.0.1/16)
                主机2(192.168.58.145) 设置docker0 网关 (172.18.0.1/16)
   修改方式 编辑 /etc/docker/daemon.json修改如下 两台主机分别设置不一样网关

{"bip":"172.18.0.1/16"}
重启docker
 
service docker restart
使用ifconfig查看docker0的ip是否修改
分别在两个主机上启动1个容器
docker run -itd --name s1  centos
分别查看ip 是否是 172.17.0.2和172.18.0.1
[root@cdh3 ~]# docker inspect s1 | grep IPA
            "SecondaryIPAddresses": null,
            "IPAddress": "172.18.0.2",
                    "IPAMConfig": null,
                    "IPAddress": "172.18.0.2",
在主机144上 要求能访问 172.18段 添加路由
route add -net 172.18.0.0 netmask 255.255.0.0 gw 192.168.58.145
在主机145上 要求能访问 172.17段 添加路由
route add -net 172.17.0.0 netmask 255.255.0.0 gw 192.168.58.145
主机两台主机的 ip_forward功能必须开启 否则不会在网卡间转发
[root@cdh2 ~]# sysctl -a | grep net.ipv4.ip_forward
net.ipv4.ip_forward = 1
如果值不是 1 修改 /etc/sysctl.conf 添加一行
net.ipv4.ip_forward = 1
执行命令 sysctl -p 生效即可  成功后 互相ping对方的docker容器的ip发现成功
模拟环境图:


3》Pipework指定静态ip

Pipework是一个简单易用的Docker容器网络配置工具。由200多行shell脚本实现。通过使用ip、brctl、ovs-vsctl等命令来为Docker容器配置自定义的网桥、网卡、路由等。
使用新建的bri0网桥代替缺省的docker0网桥
bri0网桥与缺省的docker0网桥的区别:bri0和主机网卡之间是也是veth pair 可以为容器分配和主机相同的网段静态ip
模拟环境图
  

该方式创建的容器 使用none的网络模式 自己定义网桥和网卡等 启动容器时可以通过--net=none指定容器网络模式。

安装网桥

 yum install -y bridge-utils
查看所有网桥
[root@cdh2 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242027435aa       no

修改网络文件/etc/sysconfig/network-scripts/ifcfg-eno16777736

[root@cdh2 network-scripts]# more ifcfg-eno16777736
TYPE=Ethernet
#BOOTPROTO=dhcp
BOOTPROTO=none
#IPADDR=192.168.58.144
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=eno16777736
UUID=1c2310e2-e82e-4ce7-a1aa-60d05aa47f1e
DEVICE=eno16777736
ONBOOT=yes
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
BRIDGE="br-ex"
将静态ip相关注释 添加 BRIDGE=设备名称  添加一个新的网卡文件ifcfg-br-ex 内容
[root@cdh2 network-scripts]# more ifcfg-br-ex
TYPE=Bridge
BOOTPROTO=static
IPADDR=192.168.58.144
NETMASK=255.255.255.0
GATEWAY=192.168.58.2
PREFIX=24
DNS1=192.168.58.2
NAME=br-ex
ONBOOT=yes
DEVICE=br-ex
重启网卡后 查看网络和网桥
root@cdh2 network-scripts]# ifconfig
br-ex: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.58.144  netmask 255.255.255.0  broadcast 192.168.58.255
        inet6 fe80::20c:29ff:fe90:75c5  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:90:75:c5  txqueuelen 0  (Ethernet)
        RX packets 268  bytes 24407 (23.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 136  bytes 17574 (17.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@cdh2 network-scripts]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-ex           8000.000c299075c5       no              eno16777736
docker0         8000.0242027435aa       no
下载pipework脚本
[root@cdh2 ~]# git clone https://github.com/jpetazzo/pipework.git
进入查看 其中有个文件pipework就是脚本
[root@cdh2 ~]# cd pipework
[root@cdh2 pipework]# ll
total 60
-rw-r--r-- 1 root root    75 Jun  6 11:28 docker-compose.yml
drwxr-xr-x 2 root root    23 Jun  6 11:28 doctoc
-rw-r--r-- 1 root root 11358 Jun  6 11:28 LICENSE
-rwxr-xr-x 1 root root 14698 Jun  6 11:28 pipework
-rw-r--r-- 1 root root   827 Jun  6 11:28 pipework.spec
-rw-r--r-- 1 root root 22328 Jun  6 11:28 README.md
将该脚本拷贝到/usr/local/bin目录 方便执行
[root@cdh2 pipework]# cp -rp pipework /usr/local/bin 

分别添加容器 指定 none网络模式

docker run -itd --net none --name s1  centos

给容器制定固定ip

[root@cdh2 pipework]# pipework br-ex s1 192.168.58.142/24@192.168.58.144
[root@cdh2 pipework]# ping 192.168.58.142
PING 192.168.58.142 (192.168.58.142) 56(84) bytes of data.
64 bytes from 192.168.58.142: icmp_seq=1 ttl=64 time=0.249 ms
piepework参数
pipework 网桥名称 容器名称 容器固定ip/24@网桥ip
其他机器上ping  192.168.58.142发现成功
主机2配置同上即可


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐