容器系列之docker网络

1.网络名称空间:iproute
实质:ip命令是系统内核级的操作

[root@node1 ~]# rpm -q iproute 使用网络名称空间模拟容器间的通讯使用ip命令就可以实现
iproute-4.11.0-14.el7.x86_64   使用ip去管理时,其他名称空间都是共享的,除了网络名称空间是隔离的

2.网络名称空间管理

[root@node1 ~]# ip netns add r1   添加网络名称空间
[root@node1 ~]# ip netns add r2
[root@node1 ~]# ip netns list
r2
r1
[root@node1 ~]# ip netns exec r1 ifconfig -a   exec是执行命令
lo: flags=8<LOOPBACK>  mtu 65536               没有网卡,只有一个lo
        loop  txqueuelen 1  (Local Loopback)
        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@node1 ~]# ip link add name veth1.1 type veth peer name veth1.2
[root@node1 ~]# ip link sh
24: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
name: 指定网卡的名称
veth1.1: 第一个设备的第一段
type: 类型
peer: 相邻的网卡

把其中一个网卡留在宿主机中,把另一个移动r1名称空间中

[root@node1 ~]# ip link set dev veth1.2 netns r1
[root@node1 ~]# ip link show
24: veth1.1@if23: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
[root@node1 ~]# ip netns exec r1 ifconfig veth1.2   在r1中有veth1.2
veth1.2: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 5a:06:37:1f:f2:a8  txqueuelen 1000  (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@node1 ~]# ip netns exec r1 ip link set dev veth1.2 name eth0
[root@node1 ~]# ip netns exec r1 ifconfig eth0
eth0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 5a:06:37:1f:f2:a8  txqueuelen 1000  (Ethernet)

激活虚拟网卡对

激活宿主机上的一段虚拟网卡
[root@node1 ~]# ifconfig veth1.1 10.1.0.1/24 up
[root@node1 ~]# ifconfig veth1.1
veth1.1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 10.1.0.1  netmask 255.255.255.0  broadcast 10.1.0.255
激活名称空间中的虚拟网卡
[root@node1 ~]# ip netns exec r1 ifconfig eth0 10.1.0.2/24 up
[root@node1 ~]# ip netns exec r1 ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.1.0.2  netmask 255.255.255.0  broadcast 10.1.0.255
[root@node1 ~]# ping 10.1.0.2  使用宿主机Ping名称空间
PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data.
64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.085 ms

把宿主机虚拟网络卡veth1.1移到名称空间r2中

[root@node1 ~]# ip link set dev veth1.1 netns r2
[root@node1 ~]# ip netns exec r2 ifconfig veth1.1 10.1.0.3/24 up  激活r2中的虚拟网卡
[root@node1 ~]# ip netns exec r2 ifconfig veth1.1
veth1.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
[root@node1 ~]# ip netns exec r2 ping 10.1.0.2    r2 ping r1是可以通讯的
PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data.
64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.050 ms

实现原理
描述:在宿主机上创建r1,r2两个名称空间,然后创建一对网卡为veth1.1和veth1.2,创建时就是像有一根线连接起来似的,当把一半放在r1时,就实现r1与宿主机通讯,另一半放在r2就实现两个名称空间来通讯

 

 

3.容器的四种网络类型
创建封闭式容器

[root@node1 ~]# docker run --name t0 -it --network none --rm busybox:latest
/ # ifconfig -a
lo        Link encap:Local Loopback     只有一个loop
          inet addr:127.0.0.1  Mask:255.0.0.0

创建bridge容器

[root@node1 ~]# docker run --name t0 -it --rm busybox:latest  #--rm退出会自动删除,bridge在容器之间通讯是确定的
WARNING: IPv4 forwarding is disabled. Networking will not work.
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05    正常启动有eth0网络接口
          inet addr:172.17.0.5  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
[root@node1 ~]# docker run --name t0 -it --network bridge --rm busybox:latest  #以不指定网络一样效果

设置主机名

[root@node1 ~]# docker run --name t0 -it --network bridge --rm busybox:latest
/ # hostname  
ba4083991e81  主机名,也就是容器的id
[root@node1 ~]# docker ps |grep busybox
ba4083991e81        busybox:latest      "sh"                     About a minute ago   Up About a minute                       t0
[root@node1 ~]# docker run --name t0 -it --network bridge -h t0.reid.com --rm busybox:latest
/ # hostname
t0.reid.com   在容器启动时,直接注入主机名称

容器实现主机名访问其他主机
a. 容器可以通过DNS来解析
b. 通过本地的/etc/hosts

/ # cat /etc/hosts 
172.17.0.5	t0.reid.com t0  自动生成的
/ # cat /etc/resolv.conf 
; generated by /usr/sbin/dhclient-script
search localdomain reid.com
nameserver 192.168.56.2         容器中使用的是宿主机的DNS,是物理网络
/ # nslookup -type=A www.baidu.com  可以正常解析baidu,是通过56.2解析的
Server:		192.168.56.2
Address:	192.168.56.2:53
Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 61.135.169.125
Name:	www.a.shifen.com
Address: 61.135.169.121

docker启动时直接指定dns

[root@node1 ~]# docker run --name t0 -it --network bridge -h t0.reid.com --dns 114.114.114.114 --rm busybox:latest
/ # cat /etc/resolv.conf 
search localdomain reid.com
nameserver 114.114.114.114
[root@node1 ~]# docker run --name t0 -it --network bridge -h t0.reid.com --dns 114.114.114.114 --dns-search reid.linux --rm busybox:latest
/ # cat /etc/resolv.conf 
search reid.linux
nameserver 114.114.114.114
[root@node1 ~]# docker run --name t0 -it --network bridge -h t0.reid.com --dns 114.114.114.114 --dns-search reid.linux --add-host www.reid333.com:1.2.1.1 --rm busybox:latest
/ # tail -2 /etc/hosts
1.2.1.1	www.reid333.com
172.17.0.5	t0.reid.com t0  启动时直接注入解析到/etc/hosts文件中

  

开放式容器通讯
场景:假设容器中使用nginx服务,默认情况下它是隐藏在docker0后面的,所以默认情况下使用跨主机通讯时是不通的,如果使用静态路由来解决,可以把nginx服务expose出来

-p <containerPort>
指定的容器端口映射至主机所有地址的一个动态端口(30000-32767,如果在同一个宿主机上起了多个nginx就不会冲突)
-p <hostPort>:<containerPort>        使用多个端口时,-p可以使用多次
将容器端口<containerPort>映射至指定的主机<hostPort>
-p <ip>::<containerPort>
将指定的容器端口<containerPort>映射至主机指定<ip>的端口<hostPort>

expose容器中的端口

[root@node1 ~]# docker run --name myweb --rm -p 80 reid/httpd:v0.2
[root@node1 ~]# docker inspect myweb |grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.5",
                    "IPAddress": "172.17.0.5",
[root@node1 ~]# curl 172.17.0.5  (内部访问)
dockerbusybox
[root@node1 ~]# iptables -t nat -vnL
Chain DOCKER (2 references)   nat规则是docker使用-p选项时自动生成的
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32769 to:172.17.0.5:80
[root@node3 ~]# curl 192.168.56.129:32769   访问宿主机
dockerbusybox
[root@node1 ~]# docker kill myweb      删除时会自动删除nat规则
myweb
[root@node1 ~]# iptables -t nat -vnL
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0    

指定映射的IP地址或端口

[root@node1 ~]# docker run --name myweb --rm -p 80 reid/httpd:v0.2
[root@node1 ~]# docker port myweb   查看映射关系
80/tcp -> 0.0.0.0:32770  将容器中的80端口映射到宿主机的所有地址的327790上
[root@node1 ~]# docker run --name myweb --rm -p 192.168.56.129::80 reid/httpd:v0.2  #Ip是宿主机的,::是动态,80是容器端口
[root@node1 ~]# docker port myweb
80/tcp -> 192.168.56.129:32768
[root@node3 ~]# curl 192.168.56.129:32768
dockerbusybox
[root@node1 ~]# docker run --name myweb --rm -p 80:80 reid/httpd:v0.2  #不写地址是所有地址
[root@node1 ~]# docker port myweb
80/tcp -> 0.0.0.0:80                 宿主机的所的IP和80端口
[root@node1 ~]# curl 192.168.56.129
dockerbusybox

同时指定IP和端口

[root@node1 ~]# docker run --name myweb --rm -p 192.168.56.129:80:80 reid/httpd:v0.2
[root@node1 ~]# docker port myweb
80/tcp -> 192.168.56.129:80

  

联盟式容器
使得两个容器使用共用一个名称空间,各自使用独立user ,monut ,共享pid,ipc,uts,net

[root@node1 ~]# docker run --name b0 -it --rm busybox
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05  
          inet addr:172.17.0.5  Bcast:172.17.255.255  Mask:255.255.0.0  ####
[root@node1 ~]# docker run --name b2 -it --rm busybox  正常情况
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:07  
          inet addr:172.17.0.7  Bcast:172.17.255.255  Mask:255.255.0.0
[root@node1 ~]# docker run --name b2 -it --network container:b0 -it --rm busybox  #意思是使用共享container b0的网络名称空间
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05  
          inet addr:172.17.0.5  Bcast:172.17.255.255  Mask:255.255.0.0  #####
但是文件系统还是隔离的
/ # mkdir /tmp/test1
/ # ls /tmp/   b0
test1
/ # ls /tmp/   b2为空
共享loop接口(相当于共享ipc)
b2:
/ # echo "hello reid" > /tmp/index.html
/ # httpd -h /tmp/
/ # netstat -ant|grep 80
tcp        0      0 :::80                   :::*                    LISTEN  
b0:
/ # wget -O - -q 127.0.0.1
hello reid

  

创建时使用host(宿主机)网络
优势:在宿主机上配置httpd,要配置安装,起服务,使用容器直接docker run完事

[root@node1 ~]# docker run --name b2 --network host -it --rm busybox
docker0   Link encap:Ethernet  HWaddr 02:42:E5:83:52:6B  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
eth0      Link encap:Ethernet  HWaddr 00:0C:29:0F:73:2D  
          inet addr:192.168.56.129  Bcast:192.168.56.255  Mask:255.255.255.0
/ # echo "test reid" > /tmp/index.html
/ # httpd -h /tmp/
/ # netstat -ant|grep 80
tcp        0      0 :::80                   :::*                    LISTEN    
[root@node3 ~]# curl 192.168.56.129
test reid

自定义docker的网络属性

[root@node1 ~]# systemctl stop docker
[root@node1 ~]# cat /etc/docker/daemon.json
{
    "registry-mirrors": ["https://registry.docker-cn.com"],
    "bip": "10.0.0.1/16"    #设定ip段
}
[root@node1 ~]# systemctl start docker
[root@node1 ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 10.0.0.1  netmask 255.255.0.0  broadcast 10.0.255.255  

还可以修改其他选项
[root@node1 ~]# cat /etc/docker/daemon.json
{
    "registry-mirrors": ["https://registry.docker-cn.com"],
    "bip": "10.0.0.1/16", #核心选项为big,即bridge ip,用于指定docker0桥自身的IP地址,其他选项可以通过此计算出来,除了DNS
    "fixed-cidr": "10.20.0.0/16",
    "fixed-cidr-v6": "2001:db8::/64",
    "default-gateway": "10.20.1.1",
    "default-gateway-v6": "2001:db8:abcd::89",
    "dns": ["10.20.1.2","10.20.1.3"]
}

设定外部主机连接docker
dockerd守护进程的C/S,其默认仅监听unix socket格式地址,/var/run/docker.sock;如果使用tcp套接字

[root@node1 ~]# cat /etc/docker/daemon.json
{
    "registry-mirrors": ["https://registry.docker-cn.com"],
    "bip": "10.0.0.1/16",
    "hosts": ["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"]
}
[root@node1 ~]# systemctl start docker
[root@node1 ~]# ss -tnl|grep 2375
LISTEN     0      128         :::2375                    :::*   
[root@node3 ~]# docker -H 192.168.56.129:2375 ps   #在另一台主机上测试
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@node3 ~]# docker -H 192.168.56.129:2375 image ls
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
reid/httpd               v0.2                4f752241c109        6 days ago          1.16 MB
docker422018/httpd       v0.1-1              3aa96b4f58c1        6 days ago          1.16 MB
reid/httpd               latest              3aa96b4f58c1        6 days ago          1.16 MB
reid/httpd               v0.1-1              3aa96b4f58c1        6 days ago          1.16 MB
redis                    4-alpine            db23f46600bc        10 days ago         30 MB
nginx                    1.14-alpine         14d4a58e0d2e        11 days ago         17.4 MB
busybox                  latest              e1ddd7948a1c        7 weeks ago         1.16 MB
quay.io/coreos/flannel   v0.10.0-amd64       f0fad859c909        8 months ago        44.6 MB

自定义桥

[root@node1 ~]# docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
abedd62ed28dd57e04dfb523eb963c458aea9df11cc3291554debcb0f45f1d2e
[root@node1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
d0abdc2e1fa8        bridge              bridge              local
f5b3bb476293        host                host                local
abedd62ed28d        mybr0               bridge              local
d93680d000ce        none                null                local
[root@node1 ~]# ifconfig 
br-abedd62ed28d: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.26.0.1  netmask 255.255.0.0  broadcast 172.26.255.255 
[root@node1 ~]# docker run --name t0 -it --network mybr0 busybox:latest  #直接加入mybr0网络
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:AC:1A:00:02  
          inet addr:172.26.0.2  Bcast:172.26.255.255  Mask:255.255.0.0

[root@node1 ~]# docker run --name t1 -it --network bridge busybox:latest
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
/ # ping 172.26.0.2
PING 172.26.0.2 (172.26.0.2): 56 data bytes

分析:t1与t2两个不同的容器相当于分析接了两个不同网段的虚拟交换机,在不同网段,两个容器要通信
解决方案:两个虚拟交换机的接口还是在宿主机上,而且两个都是nat bridge, 只要在宿主机上打开核心转发功能就可以实现

[root@node1 ~]# cat /proc/sys/net/ipv4/ip_forward
1 如果不行就是iptables规则

  

 

posted @ 2018-10-07 20:58  Reid21  阅读(302)  评论(0编辑  收藏  举报