Docker 容器技术初学(四)

7、Docker网络

7.1 网络名称空间

 容器一般是在1个独立的namespace里,所以我们先实践网络名称空间

下面的实践是创建1个网络名称空间r1,创建1对veth pair,把其中1个端口移动到新建的r1名称空间之中,然后为这一对veth pair配置IP地址,互相ping通。

该实验主要是验证网络名称空间之间互通,可以通过veth pair来实现,docker也利用了veth pair来实现互通。

  ip netns add r1 增加1个r1的网络名称空间

  ip netns list 查看网络名称空间

  ip netns exec r1 ifconfig -a 查看r1内的网络接口信息

  

ip link add name veth1.1 type veth peer name veth1.2 创建1对veth

       ip link set dev veth1.2 netns  r1 把veth1.2移动到网络名称空间r1

       ip netns exec r1 ip add add 10.0.1.2/24 dev veth1.2

       ip netns exec r1 ifconfig veth1.2 up

       

 ifconfig veth1.1 10.0.1.1/24 up

  宿主机上ping 10.0.1.2 能够ping通

7.2 docker容器网络互通分析

        这里先引入docker默认的网络模型bridge的方式:

我们知道容器主要通过namespace来实现UTC,PID,MNT,USR,IPC,NET的隔离,我们可以认为1个容器独占1个名称空间。那么容器既然是互相隔离的,那么网络是怎么互通的呢?

 

如上图,有两个主机Host1和Host2, 每个Host自带1个网口,1个容器,如果 c1要和c3互通,那么怎么办呢,我们可以把c1和c3的网口绑定到各自host上的 物理网卡,如图所示,就可以实现互通。     

问题是如下图如果每个主机上又新增1个容器由如何互通呢?

                                                                                

上图新增c2和c4容器,但是已经没有物理网口可以绑定,因此容器直接绑定物理网口的方式肯定是行不通的。Linux提供桥来解决这个问题(如上右图)。在host内新增1个birdge,容器通过1对veth pair也桥接到桥上,这样就解决了主机上容器没有物理端口的问题。Bridge都可以看做我们常见的hub,能够实现二层网络常见的功能。

这种架构下,主机内的容器通信,比如C1和C2,C3和C4只需要经过bridge内转发就行了,主机间的容器通信就需要借助主机的物理网口来实现。

采用bridge这种方式,C1和C3之间的访问就没那么友好了。实际上C1和C3之间的网络是不能直接通信的,是借助于iptables或者ipvs的nat的方式来实现的。举例来说:C1访问C3的web服务的80端口,首先需要把c3的80端口暴露在HOST2的物理端口E2上(假设也是80端口),那么C1访问C3的web服务时,实际上是访问HOST2的物理端口E2的80端口。首先数据包到达HOST1的bridge1,之后查询iptables的规则会发现来自C1的请求的源地址会替换成HOST1的E1的接口地址,目的地址仍然是HOST2的E2的地址,host2收到后,会根据C3的暴露在HOST2的端口号而把数据包路由给bridge2在转发给C3,C3的回包过程类似,在HOST2的e1会做一次nat,在HOST1的E1会再一次nat。

所以bridge这种网络的容器间访问是通过两次NAT来实现的。

7.3 docker 网络类型

7.3.1、查看docker网络

  docker network ls

  

   可以看到 默认有三种网络类型:

  ①、bridge

就是linux网桥,其工作原理正如前一节所讲,docker默认会生成1个叫做docker0的容器,新建的容器默认会桥接到这个docker0桥上。

       通过实验来学习docker0桥,我们看如下的网络环境:主机docker136上面运行1个container mybox1桥接在docker0上。

    

       查看容器信息:

  

docker136主机上创建了1个docker0的桥,就是那个nat桥

mybox1有1个eth0接口

docker0网桥上桥接着veth493d711,如果无法执行brctl命令,需要执行yum install -y bridge-utils来安装bridge 的管理软件

       Eth0和veth493d711构成了一对veth pair

那么docker0为什么就是1个nat桥,它是如何实现docker与外部通信的呢,答案就是它是通过iptables和ip_forward来实现的

我们可以看到iptables有一条规则表明凡是来源于172.0.0.0/16,目的地是任意的且不是到docker0自身的数据包,都要做一个MASQUERADE(伪装)操作,实际就是nat操作。172.0.0.0是docker0的桥给容器分配的地址段,这表明凡是来自容器的访问都要做nat转换。转换后会查主机路由表,从而知道需要从物理网口发送出去,发出去的数据包的源地址就是主机的物理网口的地址。

②、host 主机类型的网络

这种网络类型的容器和宿主机共用NET,IPC,UTS名称空间,因此在mybox1容器内部看到的网络接口和宿主机上的网络接口是一致的,它自己没有网络接口。

③、none 网络类型

这种网络类型的容器没有外部网络接口,只有内部lo环回接口,完全是1个网络孤岛。

7.3.2、查看docker网络的详细信息

  docker network inspect bridge

  docker network inspect host

  查看mybox1的network配置

  docker container inspect mybox1

  

7.3.3、四种容器网络架构

①、封闭式容器(none) 没有任何对外的网络接口

②、桥容器(bridge)  通过把容器通过一对veth桥接到桥上,实现相互和对外通信

③、联合式容器(container)  容器之间共享IPC,NET,UTS名称空间

④、开放式容器(host)  容器共享物理机的IPC,NET,UTS名称空间

7.3.4 测试四种容器网络

    ①、创建桥接网络的容器(bridge)

 docker container run --name mybox2 -it --network bridge --rm busybox

                                                                                桥网络       

    

②、创建封闭式网络容器(none)

 docker container run --name mybox2 -it --network none  --rm busybox

③、创建联合式容器(container)

先创建1个容器mybox2,启用http服务

docker container run --namemybox2  -it --rm busybox

mkdir -p /data

vi /data/index.html

<h1>Test combine container!</h1>

http -f -h /data

新开1个tty,再创建1个容器mybox3 和mybox2共享IPC,UTS,NET

docker container run --name mybox3 --network container:mybox2 --rm busybox

在mybox3容器内测试访问mybox2的http服务成功。表明两个是共用的 NET namespace。

wget -O - -q 127.0.0.1 可以访问http服务

④、创建开放式容器(host)

    docker container run --name mybox2 --network host -it --rm busybox

进入busybox后,可以看到container和宿主机共用网络

创建httpd目录和文件,并将http的站点目录指向过来

echo "hello container!" >> /tmp/index.html

httpd -h /tmp

然后PC浏览器访问宿主机网卡80端口,可以访问容器内的http服务

表明容器内启用的http服务使用的是宿主机的ip和端口。

7.4 外部网络访问容器

根据上面讲到的docker的四种网络类型,其中bridge和container的容器都有自己的net namespace且需要访问外部网络,且访问外部网络的方式都是nat的方式,那么外部客户端需要访问容器的某个端口怎么办呢?比如容器启用web服务,开放80端口,那么外部客户端怎么实现访问这个端口呢?答案就是:端口映射

Docker提供两种方式暴露容器的端口给外部客户端。

方式1、暴露容器指定端口给宿主机的动态端口

格式:-p portID

举例:启动nginx容器暴露80端口给宿主机的动态端口

docker container run --name myweb2 -p 80 --rm nginx:1.19-alpine

        查看nat之后的端口: iptables -t nat -vnL 或者:docker container port myweb2

可以看到容器的80端口已经映射到主机的32768端口。我们用浏览器访问主机的32768端口,可以看到我们直接访问到了容器的nginx服务。

方式2、暴露容器指定端口给宿主机某个网卡地址+指定端口

  格式:-p HostIP:hostPort:ContainerPort

举例:我们把容器的80端口暴露给宿主机的网卡10.0.0.136上的8080端口

docker container run --name myweb2 -p 10.0.0.136:8080:80 --rm nginx:1.19-alpine

可以看到容器的80端口已经映射到宿主机的8080端口,我们再次用浏览器尝试访问:

另外:除了-p选项,还有-P选项,这个选项后面不跟任何端口号,它的功能是根据镜像启动容器后,默认暴露所有在镜像配置文件里已经写好的需要暴露的端口号,启动容器时不使用这个参数,那么即使镜像内部已经配置了需要暴露端口,但是容器默认也不会暴露。(镜像制作时可以指定暴露哪些端口)

7.5 修改docker0

docker0网桥属性配置文件/etc/docker/daemon.json

docker0网络属性关键key值:

    {

“bip”: "10.1.1.1/16",

"fixed-cidr": "10.1.0.0/16",

   "fixed-cidr-v6":"2001:12F3::/64",

   "default-gateway": "10.1.1.1",

   "default-gateway-v6": "2001:12F3::1",

}

bip:设置docker0分配的ip段

"fixed-cidr":设置IPV4的cidr

"fixed-cidr-v6": 设置ipv6的cidr

"default-gateway": 设置docker0的默认ipv4网关地址

"default-gateway-v6": 设置docker0的默认ipv6网关地址

7.6 docker远程控制

开放docker服务端2375端口给外部docker客户端使用,修改/etc/docker/daemon “hosts": ["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"]  PS:要重启docker服务

 这样外部的docker客户端可以用docker -H 服务端IP:2375 来远程执行docker相关操作,显示的是服务端的容器状态。

7.7创建自定义桥

docker network create -d bridge --subnet "10.2.0.0/16" --gateway "10.2.1.1" mybr0

-d表示创建什么样的网络桥,默认是bridge

-subnet 子网范围

-gateway 网关

除了上述的docker自带的四种网络类型,实际上docker也支持overlay网络实现容器直接互通,在后续章节介绍。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值