docker网络

docker 技术不是凭空而来,而是站在linux技术基础上发起来的

chroot

将进程限定到指定的目录下,防止因程序异常对系统造成影响。在rsync-daemon / named 等程序中都有应用

cgroup

可以通过cgroup 来限制容器对资源的使用,主要时对cpu 和 内存
查询cgroup 内核对cpu的支持grep -i cgroup /boot/config-3.10.0-957.el7.x86_64

查询cgroup 内核对内存的支持grep -i mem /boot/config-3.10.0-957.el7.x86_64 |grep -i cg

查看系统对各种资源的限制 ls /sys/fs/cgroup/

当主机不够分配时。linux 会为每一个进程算一个分数,最终它会kill掉得分最高的进程(OOM Killer(Out of Memory Killer))

/proc/[pid]/oom_score_adj 
范围 -1000 ~ 1000 值越高越容易被kill掉
如果设置为 -1000 则进程永远不会被内核kill
/proc/[pid]/oom_adj 
范围 -17 ~ 15 值越高越容易被kill掉
如果设置为 -17 则进程永远不会被内核kill
/proc/[pid]/oom_score
综合计算内存、cpu、存活时间和 oom_adj得分。值越高越容易被kill掉

namespace

隔离类型 功能 系统调用参数 内核版本
Mnt NameSpace(mount) 提供磁盘挂载点和文件系统的隔离能力 CLONE_NEWNS 2.4.19
Ipc NameSpace(inter-process communication) 提供进程间通讯的隔离能力 CLONE_NEWIPC 2.6.19
Uts NameSpace(unix timesharing system) 主机名的隔离能力 CLONE_NEWUTS 2.6.19
Pid NnameSpace(process identification) 提供进程的隔离能力 CLONE_NEWPID 2.6.24
Net NameSpace(nework) 提供网络隔离能力 CLONE_NEWNET 2.6.29
User NameSpace(user) 提供用户隔离能力 CLONE_NEWUSER 3.8

下面我们单独列出容器的网络名称空间的实现隔离的过程

docker run --net=host --rm -it alpine ip a 
docker run --net=bridge --rm -it alpine ip a
docker run --net=none --rm -it alpine ip a
docker run --net=container:pause --rm -it alpine ip a
# mutil 自定义网络 可以是bridge 类型 也可以是 overlay 网络类型
docker run --net=mutil --rm -it alpine ip a

Docker创建一个容器的时候﹐就网络名称空间来说会执行如下操作∶

  1. 创建一对虚拟接口,分别放到宿主机和新容器中

  2. 虚拟网络接口一端桥接到默认的docker0或指定网桥上﹐并具有一个唯一的名字﹐如veth65f9

  3. 虚拟网络接口另一端放在容器网络名称空间中﹐并修改名字为eth0

  4. 从docker0网桥中获取一个空闲地址分配给容器的eth0,并配置默认路由到桥接网卡veth65f9

  5. 创建一对虚拟接口,分别放到宿主机和新容器中

    # 创建名称空间,模拟一个容器
    ip netns add netns0
    # 创建虚拟网络对
    ip link add A type veth peer name B
    # 把虚拟网络对的一端放置到新建的名称空间 并命名为 eth0
    ip link set A name eth0 netns netns0
    # 进入虚拟网络名称空间配置网络
    nsenter --net=/var/run/netns/netns0 bash
    ip link set eth0 up
    ip link set lo up
    ip address add 172.17.100.1/24 dev eth0
    
    # 宿主机配置虚拟网络对
    ip link set B up 
    ip address add 172.17.100.2/24 dev B
    
     ip neigh
    

    以上已经完成了跨网络名称空间的通讯

  6. 在第一步的基础上我们继续学习多网络名称空间网络通讯

    # 创建两个名称空间,模拟两个新建的容器
    ip netns add netns0
    ip netns add netns1
    
    ip link add A type veth peer name B
    ip link add C type veth peer name D
    
    ip link set A name eth0 netns netns0
    ip link set C name eth0 netns netns1
    
    nsenter --net=/var/run/netns/netns0 bash -c "ip link set eth0 up ;ip link set eth0 up; ip address add 172.17.100.1/24 dev eth0"
    
    nsenter --net=/var/run/netns/netns1 bash -c "ip link set eth0 up ;ip link set eth0 up; ip address add 172.17.100.2/24 dev eth0"
    

    主要区别在这里了,在宿主机创建了一个网桥,类似docker0

    ip link add br172 type bridge
    ip link set br172 up
    ip link set B up
    ip link set D up 
    ip link set B master br172
    ip link set D master br172
    

    此时两个名称空间已经可以互相访问,如果需要与宿主机通讯,此时已经涉及到iso 网络模型的的三层,需要配置ip 和 路由,下面我们继续学习。

    ip address add 172.17.100.254/24 dev br172
    
    # netns0 和 netns1 中设置默认路由为网桥
    nsenter --net=/var/run/netns/netns0 bash 
    ip r add default via 172.17.100.254/24
    #
    nsenter --net=/var/run/netns/netns1 bash 
    ip r add default via 172.17.100.254/24
    

    此时你的容器已经可以与宿主机的网络互通了,如果需要在容器内访问互联网,这是你应该想到了 iptables 的SNAT 功能

    iptables -t nat -I POSTROUTING -s 172.17.100.0/24 ! -o br172 -j MASQUERADE
    iptables -P FORWARD ACCEPT
    

    此时你的容器已经可以上网了,如果希望容器可以对外提供服务,比如希望对外提供httpd ,你需要配置DNAT的功能

    # 外部访问名称空间内网络
    iptables -t nat -I PREROUTING -d 10.4.7.10 -m tcp -p tcp --dport 65535 -j DNAT --to-destination 172.17.100.1:8000
    
    #
    iptables -t nat -A OUTPUT -d 10.4.7.10 -p tcp -m tcp --dport 65535 -j DNAT --to-destination 172.17.100.1:8000
    

以上是docker0网桥模式下单个宿主机各个容器通讯的过程,如果我们希望不同宿主机的容器能够互相通讯就需要是有overlay 网络模型

  1. 启动一个注册中心docker run --rm -d -p8500:8500 consul

  2. 修改dockerd的配置文件

    [root@master ~]# cat /etc/docker/daemon.json 
    {
      "cluster-store": "consul://10.4.7.12:8500",
      "cluster-advertise": "eth0:2376",
      "registry-mirrors": ["https://o957bhxb.mirror.aliyuncs.com"]
    }
    systemctl daemon-reload
    systemctl restart docker
    
  3. 创建overlay类型的网络驱动

    docker network create -d overlay multi
    
  4. 在不同的宿主机上分别启动容器

    docker run --rm -it --net=multi alpine sh
    

最后我想总结下docker network命令的使用。docker 支持CNM(container network model) 的网络模型在docker中具体实现方式就是通过docker network命令实现

删除没有用的网络 docker network prune
列出当前网络docker network ls
创建一个网桥

docker network create -d bridge my-bridge-network
docker network create bbb  --attachable  --driver bridge --subnet "192.168.0.1/24"
docker network create -d overlay my-multihost-network

连接到网桥 docker network connect my-bridge-network busybox
断开连接 docker network disconnect my-bridge-network busybox
删除网桥 docker network rm my-bridge-network
查看网桥的具体内容 docker network inspect my-bridge-network

QA

下面这个问题是有一天启动了一个容器但是忘记了使用 --publish将端口暴露出去,于是回想docker--publish的原理是通过iptables 实现的,于是使用iptables 的防火墙验证下这个想法

iptables -t nat -A PREROUTING -d 172.21.160.147  -p tcp --dport 10000 -j DNAT --to-destination 172.7.200.2:80
iptables -t nat -A POSTROUTING -s 172.7.200.2 -p tcp --sport 80 -j  MASQUERADE

你知道macvlan么,在docker中如何创建一个macvlan的网桥

  • macvlan是kernel新支持的特性之一,需要Linux kernel v3.9–3.19和4.0+的支持。
  • 这种模式所配置的网络同主机网络在同一个LAN里面,可以具有和主机一样的网络能力。
    在linux环境中手工创建macvlan 的网桥模式
 1993  ip link add link ens33 name ens33.1 type macvlan mode bridge
 1995  ethtool -i ens33.1
 1996  ip a a 10.4.7.199/24 dev ens33.1

docker network create -d macvlan -subnet=10.4.7.0/24 --gatway=10.4.7.254 -o parent=eht0 -o macvlan_mode=private testmacvlan
[root@allinone ~]# docker run -it  --net=testmacvlan alpine sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
29: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN 
    link/ether 02:42:0a:04:07:01 brd ff:ff:ff:ff:ff:ff
    inet 10.4.7.1/24 brd 10.4.7.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # 

给容器添加一个网卡,再次观察容器的网卡信息

docker network connect bridge 4902552c6e64
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
29: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN 
    link/ether 02:42:0a:04:07:01 brd ff:ff:ff:ff:ff:ff
    inet 10.4.7.1/24 brd 10.4.7.255 scope global eth0
       valid_lft forever preferred_lft forever
30: eth1@if31: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:07:c8:02 brd ff:ff:ff:ff:ff:ff
    inet 172.7.200.2/24 brd 172.7.200.255 scope global eth1
       valid_lft forever preferred_lft forever
posted @ 2021-04-22 16:53  mingtian是吧  阅读(64)  评论(0编辑  收藏  举报