您的位置:首页 > 运维架构 > Docker

Docker学习笔记之容器的四种网络模式

2017-10-27 22:40 1171 查看
首先从镜像库pull一个rhel7的镜像下来,这些东西你得玩,光看没意思。

本人pull了前两个镜像进行测试,如果连接失败可以多试几次,连上之后速度不算很差



docker pull richxsl/rhel7
docker pull bluedata/rhel7




首先温习一下前面有用到的命令

1.运行NGINX容器,并且将网站默认发布目录与真机的/tmp/website目录进行映射,方便在真机中进行开发:

docker run -it --name vm1 --net host -v /tmp/website:/usr/share/nginx/html nginx


2. 在宿主机中通过Docker执行命令查看容器ip:

docker exec vm1 ip addr


3. 批量终止或者删除容器:

# docker kill `docker ps -aq`

# docker rm `docker ps -aq`




1. 容器的四种网络模式

Docker在创建容器时有四种网络模式,bridge为默认不需要用–net去指定,其他三种模式需要在创建容器时使用–net去指定。

bridge模式,使用–net=bridge指定,默认设置。
none模式,使用–net=none指定。
host模式,使用–net=host指定。
container模式,使用–net=container:容器名称或ID指定


启动容器时可以使用 –net 参数指定,默认是桥接模式。

1.1 Bridge 桥接模式的实现步骤主要如下:



(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon将 veth1添加到 Docker Container所属的 namespace下,并被改名为 eth0。如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到Docker Container网络的联通性;同时,也保证 Docker Container单独使用 eth0,实现容器网络环境的隔离性。
bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。最明显的是,该模式下 Docker Container不具有一个公有 IP,即和宿主机的 eth0不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。虽然 NAT 模式经过中间处理实现了这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等。另外 NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。


1.2 Host 网络模式



host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然,有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。


1.3 Container 网络模式



(1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
(2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用other container 的 namespace。Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况。


1.4 None 网络模式

网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none模式为 Docker Container做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了 Docker 设计理念的开放。


接下来讲一下如何在 none 网络模式下为容器分配固定 ip:



netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络。
使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则等都是独立的,就好像进入了另外一个网络一样。


直接上命令,少点截图,少浪费点CSDN的存储

[root@lockey6 ~]# docker exec vmx ip addr | grep 192#无结果

[root@lockey6 ~]# ip link add name veth0 type veth peer name veth1#创建对等连接

[root@lockey6 ~]# brctl addif docker0 veth0#将连接的一头加到docker0

[root@lockey6 ~]# docker inspect -f '{{.State.Pid}}' vmx
4850#过滤当前容器进程号

[root@lockey6 ~]# mkdir /var/run/netns#为映射创建目录

[root@lockey6 ~]# ln -s /proc/4850/ns/net /var/run/netns/4850#做软连接/映射

[root@lockey6 ~]# ip link set veth1 netns 4850#将连接的另一头进行针对容器进行设置

[root@lockey6 ~]# docker exec vmx ip addr | grep veth1
11: veth1@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000#发现已经有网卡了

[root@lockey6 ~]# docker exec vmx ip addr | grep eth0

[root@lockey6 ~]# ip netns exec 4850 ip link set veth1 name eth0#修改网卡名称,也可不改

[root@lockey6 ~]# docker exec vmx ip addr | grep eth0
11: eth0@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000#网卡还未起来

[root@lockey6 ~]# ip netns exec 4850 ip link set eth0 up#起容器网卡

[root@lockey6 ~]# docker exec vmx ip addr | grep eth0
11: eth0@if12: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state LOWERLAYERDOWN qlen 1000

[root@lockey6 ~]# ip netns exec 4850 ip addr add 192.168.3.10/24 dev eth0#为容器网卡添加 ip

[root@lockey6 ~]# docker exec vmx ip addr | grep eth0
11: eth0@if12: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state LOWERLAYERDOWN qlen 1000
inet 192.168.3.10/24 scope global eth0

[root@lockey6 ~]# docker exec vmx ping 192.168.3.1#测试连同性,无果,因为宿主机一端未起对应网卡
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
From 192.168.3.10 icmp_seq=1 Destination Host Unreachable
From 192.168.3.10 icmp_seq=2 Destination Host Unreachable

^C[root@lockey6 ~]# ip link set veth0 up#起宿主机网卡

[root@lockey6 ~]# docker exec vmx ping 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=0.067 ms
64 bytes from 192.168.3.1: icmp_seq=2 ttl=64 time=0.124 ms

^C[root@lockey6 ~]# ping www.baidu.com
PING www.a.shifen.com (183.232.231.173) 56(84) bytes of data.
64 bytes from www.sn.10086.cn (183.232.231.173): time=47.3 ms
64 bytes from www.sn.10086.cn (183.232.231.173): icmp_seq=4 ttl=54 time=47.0 ms






虚拟机能够上网,但是容器还上不了网:

[root@lockey6 ~]# docker exec vmx ping www.baidu.com
ping: www.baidu.com: Name or service not known
[root@lockey6 ~]#


最后一步:添加网关使容器可以上网(网关即为docker0的ip):

[root@lockey6 ~]# ip netns exec 4850 ip route add default via 192.168.3.1




其实以上命令摘出来主要步骤然后一键脚本执行就可以了,这里只是为了做讲解和效果展示

常用的 namespace 的命令:

1. 添加一个 namespace
ip netns add [name]
2. 在 namespace 中启用一个设备
ip netns exec [name] ip link set lo up
3. 在 namespace 中新加一个设备
ip link set [dev-name] netns [name]
启用:
ip netns exec [name] ip link set [dev-name] up
4. 查看指定 namespace 中指定设备的参数信息
ip netns exec [name] ip addr show [dev-name] permanent scope global
5. 为 namespace 中指定设备设置 ip
ip netns exec [name] ip -4 addr add 192.168.1.2/24 brd 192.168.1.255 scope global dev
[dev-name]
6.查看所有 network namespace
ip netns list
7.ping 虚拟机实例
ip netns exec [name] ping 192.168.1.3


添加固定 IP 的 Shell 脚本:

#/bin/bash
if [ -z $1 ] || [ -z $2 ] || [ -z $3 ] || [ -z $4 ] || [ -z $5 ];
then
echo "*****Input the necessary parameters: CONTAINERID IP MASK GATEWAY
ETHNAME"
echo "*****Call the script like: sh static_ip.sh vm1 192.168.1.10 24 192.168.1.1 veth0"
exit
fiCONTAINERID=$1
SETIP=$2
SETMASK=$3
GATEWAY=$4
ETHNAME=$5
#判断宿主机网卡是否存在
ifconfig $ETHNAME > /dev/null 2>&1
if [ $? -eq 0 ]; then
read -p "$ETHNAME exist,do you want delelte it? y/n " del
if [[ $del == 'y' ]]; then
ip link del $ETHNAME
else
exit
fi
fi
#
pid=`docker inspect -f '{{.State.Pid}}' $CONTAINERID`
mkdir -p /var/run/netns
find -L /var/run/netns -type l -delete
if [ -f /var/run/netns/$pid ]; then
rm -f /var/run/netns/$pid
fi
ln -s /proc/$pid/ns/net /var/run/netns/$pid
#
ip link add $ETHNAME type veth peer name B
brctl addif br3 $ETHNAME
ip link set $ETHNAME up
ip link set B netns $pid
#先删除容器内已存在的 eth0
ip netns exec $pid ip link del eth0 > /dev/null 2>&1
#设置容器新的网卡 eth0
ip netns exec $pid ip link set dev B name eth0
ip netns exec $pid ip link set eth0 up
ip netns exec $pid ip addr add $SETIP/$SETMASK dev eth0
ip netns exec $pid ip route add default via $GATEWAY


容器端口映射:

[root@lockey6 ~]# docker run -p 8000:80 -p 8001:443 -it --name web nginx bash






通过宿主机ip:8000进行访问



我们修改下默认发布页:





Docker 的端口映射是由 iptables 来实现的



容器间互联:

--link 参数可以在不映射端口的前提下为两个容器间建立安全连接, --link 参数可以连接一个或多个容器到将要创建的容器。
--link 参数的格式为 --link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名

docker run -it --name web2 --link web:alias nginx bash


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: