Docker 虚拟化技术底层基于 LXC+Cgroups+AUFS ( Overlay)技术实现,而Cgroups 是Linux内核提供的一种可以限制、记录、隔离进程组(Process Groups)所使用的物理资源的机制。
Docker虚拟化的产物是Docker 容器,基于Docker Engine启动容器时,默认会给容器指定和分配各种子系统,如CPU子系统、Memory子系统、I/O子系统、NET子系统等。
启动一个容器,会为Network Namespace(子系统)提供一份独立的网络环境,包括网卡、路由、Iptables规则等,容器与其他容器的Network Namespace是相互隔离的。
通过 Docker run命令创建 Docker容器时,可以使用--net选项指定 Docker容器的网络模式,Docker默认有4种网络模式。
(1)Host模式,使用--net=host指定。
(2)Container模式,使用--net=container:NAME_or_ID指定。
(3)None模式,使用--net=none指定。
(4)Bridge模式,使用--net=bridge指定,默认设置。
4.1 Host模式剖析
通常来讲,启动新的 Docker容器,都会分配独立的Network Namespace隔离子系统;如果在运行时指定为Host模式,那么 Docker容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace子系统。
新创建的 Docker容器不会创建自己的网卡,不会再虚拟出自己的IP、网关、路由等信息,而是和宿主机共享IP和端口等信息,其他软件、目录还是相互独立的。两个容器除了网络方面相同之外,其他如文件系统、进程列表等还是相互隔离的。
4.2 Container 模式剖析
Container模式是指定新创建的 Docker 容器和已存在的某个 Docker 容器共享一个NetworkNamespace子系统,而不是和宿主机共享。
新创建的 Docker 容器不会创建自己的网卡,不会再虚拟出自己的网卡、IP、网关、路由等信息,而是和指定的Docker容器共享P和端口等信息,其他软件、目录还是相互独立的。两个容器除了网络方面相同之外,其他如文件系统、进程列表等还是相互隔离的。如果依附的 Docker容器关闭,新的 Docker容器网络也会丢失。
4.3 None模式剖析
None模式与其他模式都不同。如果 Docker 容器使用None模式,Docker 容器会拥有自己的Network Namespace子系统,但是 Docker引擎并不会为新启动的Docker容器配置任何的网络信息。
即新创建的Docker 容器不会虚拟出自己的网卡、IP、网关、路由等信息,而是需要手动为Docker 容器添加这些信息。在企业实战环境中,通常会使用Pipework工具为Docker容器指定IP等信息。
4.4 Bridge模式剖析
Docker 容器的Bridge模式也是 Docker默认的网络模式。该模式会为每个容器分配NetworkNamespace子系统,会自动给每个容器虚拟出自己的网卡、IP、网关、路由等信息,无须手动添加。
默认创建的Docker 容器会统一通过一对veth 虚拟网卡连接到一个虚拟网桥交换机DockerO上,所有的容器的网络加入一个二层交换机网络,即同一宿主机的所有容器都是可以相互联通和访问的。
4.5 Bridge模式原理剖析
默认 Docker引擎启动会在本地生成一个 Docker0虚拟网卡。Docker0是一个标准 Linux虚拟网桥设备。在 Docker 默认的桥接网络工作模式中,Docker0网桥起至关重要的作用。物理网桥是标准的二层网络设备,标准物理网桥只有两个网口,可以将两个物理网络连接在一起。
但与物理层设备集线器等相比,网桥具备隔离冲突域的功能。网桥通过MAC地址学习和泛洪的方式实现二层相对高效的通信。随着技术的发展,标准网桥设备已经基本被淘汰了,替代网桥的是二层交换机。二层交换机也可以看成一个多口网桥。
Docker容器采用Bridge模式结构,如图4-1所示。
图4-1 Docker容器Bridge模式结构
Docker Bridge模式创建过程如下。
(1)启动Docker 容器,指定模式为桥接模式时(默认模式),Docker 引擎会创建一对虚拟网卡 veth 设备,veth 设备总是成对出现,组成一个数据的通道,数据从一个设备进入,就会从另一个设备出来。veth 设备常用来连接两个网络设备,可以把 veth 接口对认为是虚拟网线的两端。
(2) veth 设备的另外一端放在新创建的容器中,命名为eth0;然后将另外一块设备放在宿主机中、以类似 vethxxx的名称命名,并将这个网络设备加人Docker0网桥。
(3)Docker 引擎会从 DockerO子网中动态分配一个新的P给容器使用,并设置Docker0的IP地址为容器的默认网关。
(4)新创建的容器与宿主机能够通信,宿主机也可以访问容器中的IP地址。在Bridge模式下,连在同一网桥(交换机)上的容器之间可以相互通信,同时容器也可以访问外网(基于iptablesSNAT)。但是其他物理机不能访问Docker容器IP,需要通过NAT将容器IP的port 映射为宿主机的IP和 port。
4.6 Bridge模式实战一
基于 Docker引擎启动Nginx Web容器,默认以 Bridge方式启动Docker容器,会动态地给Docker容器分配IP、网关等信息,操作指令如下:
#查看镜像列表
docker images
#运行新的Nginx容器
docker run -itd docker.io/nginx:latest
#查看启动的Nginx容器
docker ps
#查看Nginx容器的IP地址
docker inspect 510ea29c39f6|grep -i ipaddr
#访问Nginx容器80端口服务 curl -I http://172.17.0.2/
4.7 Bridge模式实战二
基于Docker引擎启动Nginx Web容器,默认以Bridge方式启动Docker容器,此处使用pipework工具手动给容器指定桥接网卡,并手动配置IP地址。操作指令如下:
#查看镜像列表
docker images
#运行新的Nginx容器
docker run -itd --net=none docker.io/nginx:latest
#查看启动的Nginx容器
docker ps
#查看Nginx容器的IP地址(没有IP地址)
docker inspect 265a3745752e|grep -i ipaddr
#安装pipework IP配置脚本工具,方法如下
#安装pipework
git clone https://github.com/jpetazzo/pipework
cp ~/pipework/pipework /usr/local/bin/
#查看pipework工具是否配置正确
pipework -h
#pipework工具手动指定容器的IP,并设置容器为桥接方式上网,命令如下(docker0为网桥
#名称,172.17.0.18/16为容器IP和掩码,172.17.0.1为容器网关)
pipework docker0 265a3745752e 172.17.0.18/16@172.17.0.1
ping 172.17.0.18 -c 2
curl -I http://172.17.0.18/
4.8 Bridge模式实战三
基于Docker引擎启动Nginx Web容器,默认以Bridge方式启动Docker容器;Docker0的网桥IP为172.17.0.0/16网段,可以通过指令修改Docker网桥的IP网段。例如,将网桥IP段修改为10.10.0.1/16段,操作指令如下:
#删除原有网络信息
service docker stop
ip link set dev docker0 down
brctl delbr docker0
iptables -t nat -F POSTROUTING
#添加新的Docker0网络信息
brctl addbr docker0
ip addr add 10.10.0.1/16 dev docker0
ip link set dev docker0 up
#配置Docker的文件
cat>/etc/docker/daemon.json<<EOF
{"registry-mirrors": ["http://docker-cn.docker.com"],
"bip": "10.10.0.1/16"
}
EOF
#启动新的Docker容器,查看容器桥接网络IP地址
docker run -itd docker.io/nginx:latest
docker inspect 72fec5ccdf73|grep -i ipaddr
4.9 Bridge模式实战四
为了实现Docker容器与局域网通信,并实现局域网其他的物理机也可以访问容器的IP(不配置NAT映射),可以自定义桥接网络br0,将br0与物理网卡eth0或ens33桥接。操作方法如下:
#添加ens33网卡指定bridge桥接网卡名称br0
cd /etc/sysconfig/network-scripts/
#配置ifcfg-ens33网卡
cat>ifcfg-ens33<<EOF
TYPE="Ethernet"
DEVICE="ens33"
ONBOOT="yes"
BRIDGE="br0"
IPADDR=10.0.0.122
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
EOF
#配置ifcfg-br0网卡
cat>ifcfg-br0<<EOF
DEVICE="br0"
BOOTPROTO=static
ONBOOT=yes
TYPE="Bridge"
IPADDR=10.0.0.122
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
EOF
#重启network网络服务
service network restart
#修改Docker引擎,使用br0网桥
cat /etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS="-b=br0"
#安装&部署pipework工具
yum install -y git
git clone https://github.com/jpetazzo/pipework
cp ~/pipework/pipework /usr/local/bin/
#启动Docker容器,设置为none模式,然后使用br0网桥,指令如下
#(br0为网桥名称,192.168.0.11/24为容器IP和掩码,10.0.0.122为容器网关)
docker run -itd --net=none --name=nginx-v1 docker.io/nginx pipework br0 nginx-v1 192.168.0.11/24@10.0.0.122
4.10 Docker持久化固定器IP
基于Docker引擎创建Docker容器,在默认条件下创建容器是 Bridge模式。启动容器IP地址是 DHCP随机分配且为递增的,容器之间可以互相通信,网段也是固定的。
Docker容器一旦关闭再次启动,就会导致容器的IP地址再次随机分配,而部分容器在部署的时候是不需要互相通信的,所以应使用固态 IP,保证想要通信的容器在同一网段,且容器重启之后P地址也不会随之改变。
根据4.9节的 Pipework脚本可以给Docker容器配置固定IP地址,但是重启也会丢失IP地址,有没有方法实现重启容器IP也不丢失呢?持久化固定IP地址操作方法如下。
(1)安装桥接工具和 Docker-py程序,操作指令如下:
#安装Docker-py程序
#pip install docker-py
yum install python-docker*
#安装桥接扩展包
yum install bridge-utils -y
(2)从Github仓库下载Docker-static-ip固定IP的脚本,操作指令如下:
#下载docker-static-ip脚本
git clone https://github.com/lioncui/docker-static-ip
#部署docker-static-ip程序
mv docker-static-ip /usr/local/
#启动Docker引擎服务
systemctl start docker.service
#后台启动duration脚本
cd /usr/local/docker-static-ip/
python duration.py
#查看Python脚本进程
ps -ef|grep -aiE duraion
(3)新增配置br0桥接网络。
vi ifcfg-ens33内容修改如下:
cat>/etc/sysconfig/network-scripts/ifcfg-ens33 <<EOF
DEVICE=ens33
BOOTPROTO=static
ONBOOT=yes
TYPE=Ethernet
BRIDGE="br0"
IPADDR=192.168.1.151
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
EOF
vi ifcfg-br0内容如下:
cat>/etc/sysconfig/network-scripts/ifcfg-br0 <<EOF
DEVICE="br0"
BOOTPROTO=static
ONBOOT=yes
TYPE="Bridge"
IPADDR=192.168.1.151
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
EOF
启动Docker服务,命令操作如下:
service docker restart
(4)基于本地CentOS 7镜像启动CentOS云主机,网络模式选择--net=none即可,操作指令如下:
docker run -itd --net=none --privileged --name=jfedu-vm01 centos7-ssh:v1
(5)在/usr/local/docker-static-ip/目录下,将需要给CentOS容器配置的静态IP写入containers.cfg文件即可,内容如下:
jfedu-vm01,br0,192.168.1.101/24,192.168.1.2
(6)查看Docker容器的IP地址,此时就是192.168.1.101,命令如下:
docker exec jfedu-vm01 ifconfig
(7)重启Docker容器,再次查看容器的IP地址,还是192.168.1.101,IP固定成功。
docker restart jfedu-vm01
docker exec jfedu-vm01 ifconfig
(8)通过CRT或者Xshell远程登录创建的CentOS云主机。