Docker第四篇Docker容器网络相关知识全解析

Posted 毛奇志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker第四篇Docker容器网络相关知识全解析相关的知识,希望对你有一定的参考价值。

文章目录

一、前言

二、计算机网络

2.1 计算机网络理论知识

对于软件工程来说,只能接触到上层的网络协议,包括应用层和传输层,一般是 http dns tcp udp
对于网络工程来说,一般接触到下层的网络协议,包括网络层和数据链路层

网卡是计算机网络通信的基础,linux上,通过 ifconfig 或者 ip a 查看Linux上的网卡,查看网卡的ip

lo 本地网络
eth0 与互联网通信的网卡
eth1 与局域网通信的网卡
docker docker的网卡

2.2 Linux网卡灵活操作

2.2.1 网卡配置文件

各个网卡的作用:计算机能与外界通信的硬件支持,每个网卡有唯一的MAC地址。
各个网卡的配置文件(该配置文件可以修改):在Linux中网卡对应的其实就是文件,所以找到对应的网卡文件即可,比如:cat /etc/sysconfig/network-scripts/ifcfg-eth0

cd  /etc/sysconfig/network-scripts/

2.2.2 网卡上增删IP地址

这里 lo 是本地网卡,ens33是与互联网通信的网卡,同一个网卡上可以挂多个IP地址的,现在我们在 ens33

cat /etc/sysconfig/network-scripts/ifcfg-ens33

# IP地址的查看、新增和删除操作

ip addr
ip addr add 192.168.100.251/24 dev ens33
ip addr delete 192.168.100.251/24 dev ens33


ip addr delete 192.168.100.251/24 dev ens33

2.2.3 网卡状态:UP DOWN UNKNOWN

ifdown ens33
ifup ens33

小结:关于Linux上网卡操作,包括
(1) 网卡配置文件
(2) 网卡绑定IP地址
(3) 网卡状态:UP DOWN UNKNOWN

三、Network Namespace

3.1 Network Namespace

docker = 网卡 + namespace

每个docker container 通过 namespace/cgroup 来实现隔离,network namespace的管理:

ip netns list    # 查看本机docker的network namespace列表
ip netns add ns1   # 新增本机docker的network namespace
ip netns delete ns1  # 删除本机docker的network namespace
ip netns exec ns1 ip a  # 查看本机docker的network namespace上面的IP列表

查看一下新建network namespace,这里发现会默认自带一个 lo 本地网卡

ip netns exec ns1 ip a

Docker中的network namespace 上面的本地网卡 lo 就是根据 linux 上的本地网卡 lo 创建的

所以,如下,网络隔离出来了(linux的网络隔离和 network namespace (ns1) 的网络隔离)

ip netns exec ns1 ip link show

无论是linux还是 docker network namespace ,lo 都是表示 回环地址/本地地址

network namespace 创建就默认带了一个 lo 本地回环地址


网卡是开发人员能接触的操作网络的单元,需要增加一个通信的网卡,将两个 network namespace , ns1 ns2 实现通信,即如下效果

这种技术就是 veth pair ,英文全称 Vitual Ethernet Pair ,使用这样创建出来就是默认能够连通的,表示一次创建成对的两个可以通信的网卡,分别给 ns1 ns2,即如下:

创建一对(两个)可以通信网卡,分别给ns1 和 ns2 ,这两个 network namespace 就可以通信了

创建一个pair 然后分配给ns

ip link add veth-ns1 type veth peer name veth-ns2
ip link show

创建好了,分配

ip link show
ip link set veth-ns1 netns ns1
ip link show
ip netns exec ns1 ip link

继续,将 veth-ns2 分配给 ns2

ip link show
ip link set veth-ns2 netns ns2
ip link show
ip netns exec ns2 ip link

完成了,pair技术

开始给ns1 ns2 新增的 veth-pair 网卡 新增 ip 地址,如下:

# 给network namespace ns1 添加 IP 地址 (IP地址和设备名/网卡名)
ip netns exec ns1 ip addr add 192.168.100.11/24 dev veth-ns1
ip netns exec ns1 ip a
# 给network namespace ns1 启用网卡 veth-ns1
ip netns exec ns1 ip link set veth-ns1 up
ip netns exec ns1 ip a

ip link # 查看简要IP信息
ip a  # 查看详细IP信息

同样给 ns2 也加上

ip netns exec ns2 ip addr add 192.168.100.12/24 dev veth-ns2
ip netns exec ns2 ip a
ip netns exec ns2 ip link set veth-ns2 up
ip netns exec ns2 ip a

好了 ip地址有了

/24 前面就是具体的全的ip地址,不是三位

ip netns exec ns1 ping 192.168.100.12
ip netns exec ns2 ping 192.168.100.11

两个ip地址 ping ,ping通了

完成这个图片的需求,如下:

3.2 从 Network Namespace 转到 Docker Container

docker run -d --name tomcat01 -p 8081:8080 tomcat
docker run -d --name tomcat02 -p 8082:8080 tomcat
docker stop container-id  # docker ps 查看  container-id 
docker rm container-id  # docker ps 查看  container-id


两个独立的容器可以ping通 底层是network namespace支持的

解释:创建的容器默认带了一个 network namespace

两个docker容器,虽然网络可以通,但是不是 pair 技术。

理由:两个容器内使用 ip a 查看,发现两个tomcat 的网卡不同,所以是两个network namespace ,如下图

这里使用的是 docker exec -it tomcat01 ifconfig 和 docker exec -it tomcat02 ifconfig ,查看到的是两个container的ip,也可以使用 docker exec -it tomcat01 ip a 和 docker exec -it tomcat02 ip a ,查看两个container的网卡

docker exec -it tomcat01 ip a 
docker exec -it tomcat02 ip a 

对于 veth-pair 技术来说,网卡一定名称是连续的才是一对,比如,这就是一对pair的组件

则两个container 建立计算机网络通信是通过linux中转的(而不是像两个network namespace一样,直接通信),如下:


我们开始验证一下上图,即 两个container 建立计算机网络通信是通过linux中转的 。

yum install bridge-utils
brctl show
ip a

所以,docker0 tomcat01 mysql tomcat02 四个的ip地址应该是同一网段的,下图是 Docker 通信的精髓

如果在增加一个 mysql或者tomcat03 ,那么 linux 的 docker0 上应该再增加一个网卡,一个 veth-pair 对

验证一下

docker run -d --name tomcat03 -p 8083:8080 tomcat  # linux执行,运行tomcat03
docker exec -it tomcat03 bash  # linux执行,进入tomcat03
apt-get update   # tomcat03容器内执行,更新apt-get
apt-get install net-tools  # tomcat03容器内执行,安装ifconfig命令
apt-get install iputils-ping  # tomcat03容器内执行,安装ping命令
ifconfig      # tomcat03容器内执行,查看tomcat03的ip地址
ping 172.17.0.2  # tomcat03容器内执行:ping tomcat01
ping 172.17.0.3  # tomcat03容器内执行:ping tomcat02
ip a   # linux执行,查看linux上的网卡是不是增加了一个
brctl show   # linux执行,查看linux的桥接docker0下面的网卡是不是增加了一个
docker network ls  # linux执行,查看linux的network namespace

docker 各个container 通过这个docker0 通信,桥接两结果 (底层 veth-pair 技术)
(1) linux 到 container可以通
(2) container1 到 container2 可以通

3.3 自定义Network Namespace

docker0 使用的是 桥接的网络的,是桥接在linux上的打点

docker0 是一个bridge类型

docker network ls
docker network inspect bridge

也可以自己创建一个 bridge类型的

docker network ls
docker network create my-net
docker network ls

docker network inspect my-net

使用刚刚新建的自定义的network namespace,如下

docker network create tomcat-net
docker network ls
docker run -d --name custom-net-tomcat --network tomcat-net tomcat
docker exec -it custom-net-tomcat bash
apt-get update
apt-get install net-tools
apt-get install iputils-ping
exit
docker exec -it custom-net-tomcat ifconfig
docker network ls
docker network inspect tomcat-net


默认生成的docker0 是一个bridge类型的网络,如果 docker run 这里的 --network 不指定就是docker0

两个container不是同一个linux网卡,一个是默认网卡bridge,一个是自定义网卡 tomcat-net ,这种情况下相互ping不通

docker exec -it custom-net-tomcat ping 172.17.0.3

一个是docker0(即bridge) 一个custom-net-tomcat

3.4 不同network namespace通信

如果容器太多了,这个网段下面放满了, 一个 bridge 不够用,应该怎么办

重新创建另一个 bridge ,但是这个bridge 上的container 和 之前bridge 上的container 是网络不通的

ping ip 这种只有一行就是不通,control+c 会得到 100% loss
ping 域名 这种只有一行是域名解析对了,只是 ip 网络不同而已


上图中,两个红色的表示 linux 上的两个 bridge,白色表示 docker container 容器

# docker network connect 是 network 添加命令,写死 (docker network 是命令,加上connnet表示添加)
# 第一个参数 tomcat-net 表示network namespace,第二个参数 tomcat01 表示 containr-name 
# 表示将 container-name 使用这个 network namespace
docker network connect tomcat-net tomcat01
docker network ls
docker network inspect tomcat-net
docker exec -it custom-net-tomcat ping 172.19.0.3
docker exec -it tomcat01 ifconfig

3.5 通过名称访问

不是网络不通,是域名解析不了,默认的桥接 bridge/docker0 是不带域名解析能力的,但是自定义/自己创建的network namespace是带有域名解析能力的

用 自定义的 network namespace 新建两个容器,发现可以根据名称 ping 通



同一桥接,docker0里面的两个container 名字解析不了
但是自定义的桥接,里面的两个container 名字可以解析 自定义的bridge默认增加一条dns解析

在默认的 docker0 里面,可以用 --link 这种单向的

小结:生产上更加推荐 自定义bridge ,而不是 docker0 + 单向link 来完成
自定义bridge 类似于 k8s 的namespace,可以按 名字 来访问
局限:所有的docker都在同一台 centos 机器上

一个容器可以绑定两个bridge ,完成与另一个 bridge 的container 通信

3.6 端口映射:容器的端口映射到的centos

现在所有的网络通信都是
(1) centos 与 容器container 的通信(ping)
(2) 容器container 与 容器container 的通信(ping)

现在还需要 外网windows 与 容器container 的通信,我们知道,外网windows和宿主机centos是可以通信的,要想和container通信,就是需要将container的端口映射到centos就可以了

实际上我们已经做了

docker run -d --name tomcat01 -p 8081:8080 tomcat
docker run -d --name tomcat02 -p 8082:8080 tomcat
docker run -d --name tomcat03 -p 8083:8080 tomcat

http://192.168.100.151:8081
http://192.168.100.151:8082
http://192.168.100.151:8083

四、其他两种类型的网络:host和null



host : 该容器的ip 直接将 宿主机的ip 抄袭过来

优点:不需要 端口映射了 host = bridge + 端口映射
缺点:centos 端口是有限的,不需要暴露出来的,就不要使用 host

null: 只有本地回环地址,这个docker container从来不与外界通信


五、两个机器/机器间 container运行在不同的centos中

需求:container运行在不同的centos中,两个机器/机器间 docker container的通信

同一机器:network namespace,三种网络方式 bridge host null
不同机器:NAT 网络地址转换 vxlan

vxlan
多机网络通信的问题,底层的一个实现技术是:overlay

docker 上第四种网络技术 overlay vxlan,如下图:

六、总结全文学到的命令操作

总结一下和计算机网络网络有关的linux命令和docker命令,如下:

6.1 linux操作 (ip和网卡)

# ip地址的查看、新增、删除
ifconfig   
ip addr (也可以写成 ip a,ip a是简写)
ip addr add 192.168.100.251/24 dev ens33
ip addr delete 192.168.100.251/24 dev ens33

# 网卡配置文件(一个网卡一个配置文件)
cd  /etc/sysconfig/network-scripts/  (查看配置文件,白色是文件,绿色可执行文件,蓝色目录)

# 网卡的启用和停止 (网卡三种状态 up down unknown)
ifdown ens33
ifup ens33

6.2 network namespace操作

docker ( 从network namespace 到 docker container 的桥接网络,底层技术都是 veth-pair 这种一对网卡的方式,前者network namespace之间是直接通,后者docker container之间是通过linux实现网络通信)

# network namespace 

ip netns list    # 查看本机docker的network namespace列表
ip netns add ns1   # 新增本机docker的network namespace
ip netns delete ns1  # 删除本机docker的network namespace
ip netns exec ns1 ip a  # 查看本机docker的network namespace上面的IP列表(简要)(默认自带一个 lo 本地网卡)
ip netns exec ns1 ip link show  # 查看本机docker的network namespace上面的IP列表(简要)(默认自带一个 lo 本地网卡)

小结:network namespace的命令都是 ip netns 固定开头,然后就是 list 查询列表,add 新增, delete 删除,还有 exec ns-name 表示查看某个网络命名空间的具体信息 (ip addr是详细(包含ip),ip link show是简要(不包含ip))

# 创建一个 veth-pair 对,包含两个网卡,这两个网卡可以相互通信,将这两个网卡分配给两个network namespace

# 在linux机器上,新建一个 veth-pair 关键字是 add xxx type xxx name xxx
ip link add veth-ns1 type veth peer name veth-ns2 
ip link show      # 查看linux上的网卡信息,ip addr (ip a)/ ip link show (ip link)/ ifconfig 

ip link show      # 查看linux上的网卡信息,ip addr (ip a)/ ip link show (ip link)/ ifconfig 
ip link set veth-ns1 netns ns1   # 将linux的网卡 veth-ns1 使用到 网络命名空间 ns1 上
ip link show      # 查看linux上的网卡信息,ip addr (ip a)/ ip link show (ip link)/ ifconfig 
ip netns exec ns1 ip link   # 查询指定命名网络命名空间的简要信息



ip link show     # 查看linux上的网卡信息,ip addr (ip a)/ ip link show (ip link)/ ifconfig 
ip link set veth-ns2 netns ns2   # 将linux的网卡 veth-ns2 使用到 网络命名空间 ns2 上
ip link show     # 查看linux上的网卡信息,ip addr (ip a)/ ip link show (ip link)/ ifconfig 
ip netns exec ns2 ip link   # 查询指定命名网络命名空间的简要信息


# 给network namespace ns1 添加 IP 地址 (IP地址和设备名/网卡名)
ip netns exec ns1 ip addr add 192.168.100.11/24 dev veth-ns1  # 指定网络命名空间指定网卡上听添加IP地址
ip netns exec ns1 ip a     # 查询指定命名网络命名空间的详细信息
# 给network namespace ns1 启用网卡 veth-ns1
ip netns exec ns1 ip link set veth-ns1 up  # 指定网络命名空间启用网卡
ip netns exec ns1 ip a     # 查询指定命名网络命名空间的详细信息


ip netns exec ns2 ip addr add 192.168.100.12/24 dev veth-ns2  # 指定网络命名空间指定网卡上听添加IP地址
ip netns exec ns2 ip a      # 查询指定命名网络命名空间的详细信息
ip netns exec ns2 ip link set veth-ns2 up   # 指定网络命名空间启用网卡
ip netns exec ns2 ip a       # 查询指定命名网络命名空间的详细信息

小结:一个linux机器上,有多个网络命名空间 (网络命名空间可以新建删除查询列表,并可以查询每个网络命名空间的详细和简要信息);一个网络命名空间可以挂上多个网卡,一个 veth-pair 对是两个网卡,可以通信的两个网卡;一个网卡可以有多个IP地址。

小结:linux – 网络命名空间 – 网卡 – IP地址

6.3 docker container 的桥接网络相关操作

yum install bridge-utils
brctl show
ip a
# 命令是docker network,可以查询列表,可以新建和删除,还可以查询这个network里面有哪些container
docker network ls
docker network create my-net
docker network ls
docker network inspect my-net
docker run -d --name tomcat03 -p 8083:8080 tomcat  # linux执行,运行tomcat03
docker exec -it tomcat03 bash  # linux执行,进入tomcat03
apt-get update   # tomcat03容器内执行,更新apt-get
apt-get install net-tools  # tomcat03容器内执行,安装ifconfig命令
apt-get install iputils-ping  # tomcat03容器内执行,安装ping命令
ifconfig      # tomcat03容器内执行,查看tomcat03的ip地址
ping 172.17.0.2  # tomcat03容器内执行:ping tomcat01
ping 172.17.0.3  # tomcat03容器内执行:ping tomcat02
ip a   # linux执行,查看linux上的网卡是不是增加了一个
brctl show   # linux执行,查看linux的桥接docker0下面的网卡是不是增加了一个
docker network ls  # linux执行,查看linux的network namespace
# 都是network namespace,只是前者是在docker里面的network namespace,后者是不在docker里面的network namespace
# 一个网络命名空间network namespace就是表示一个网关,下面可以有多个docker container
docker network list   # 有实用性,表示的是网关列表/网络命名空间列表,每个网关下面可以有多个docker container
ip netns list   # 无实用性,表示的网关列表/网络命名空间列表,与docker container关闭不紧密

network namespace 单独使用,不接入到docker container,没有三种网络类型之说
接入到docker container,就有了 bridge host null 三种类型

增加或删除一个桥接,其实就是增加或删除一个网络命名空间
同一桥接内可以通信,就是同一网络命名空间内可以通信,就是同一网关可以通信,就是同一子网内可以通信,这是可以解释的通的

一个linux机器上可以有多个桥接/多个网络命名空间,一个桥接可以有多个网卡,一个网卡可以有多个IP地址

linux – 桥接(网络命名空间) – 网卡 – IP

桥接增删查改 (就是网络命名空间的增删查改)

docker network ls
docker network create my-net
docker network ls
docker network inspect my-net

brctl show  # 查看桥接列表(一个桥接可以有多个网卡)

网卡增删查改 (这里指linux上的网卡增删查改,主要是查)

查看linux上的网卡信息
ip addr (ip a)/ ip link show (ip link)/ ifconfig 

每次增加一个容器 tomcat03 ,就会增加 一个 veth-pair ,两个网卡,一个在tomcat03上,一个在linux上,此时 brctl show 列表也可以看到多了一个网卡,就是linux上增加的那个网卡, ip addr 也可以看到多了一个网卡,就就是 linux 上增加的那个网卡 (但是不会增加一个桥接,所以 docker network list 不会增加,brctl show 也不会增加)

6.4 单机 docker container 的其他两种网络通信方式(host null)

host : 该容器的ip 直接将 宿主机的ip 抄袭过来

优点:不需要 端口映射了 host = bridge + 端口映射
缺点:centos 端口是有限的,不需要暴露出来的,就不要使用 host

null: 只有本地回环地址,这个docker container从来不与外界通信

七、尾声

Docker容器网络相关知识全解析,完成了。

以上是关于Docker第四篇Docker容器网络相关知识全解析的主要内容,如果未能解决你的问题,请参考以下文章

[第四篇]——Windows Docker 安装之Spring Cloud直播商城 b2b2c电子商务技术总结

Docker_04_Docker容器网络相关知识全解析

Docker第四篇 Docker仓库管理

Docker系列-第四篇Docker镜像

docker全解

Docker第四回(容器虚拟化网络)