7.Docker网络
通过网盘分享的文件:MD文档笔记
链接: https://pan.baidu.com/s/1ao2wfyLEdN50YmIqdzfGYQ?pwd=5w5z 提取码: 5w5z
–来自百度网盘超级会员v6的分享
一.网络介绍
我们知道docker的隔离性,网络也是隔离性的一部分,linux使用了命名空间来进行资源的隔离
比如
-
pid namespace就是用来隔离进程的 -
mount namespace是用来隔离文件系统的 -
network namespace是用来隔离网络的每一个
network namespace都提供了一个独立的网络环境包括网卡、路由、iptable规则等等,都是与以其它的network space隔离的
1.Network Namespace
Docker 网络的底层原理是 Linux 的Network Namespace,所以对于 Linux Network Namespace 的理解对 Docker 网络底层原理的理解非常重要
1.1.简介
Network Namespace 是Linux 内核提供的用于实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,每个独立的网络空间内的防火墙、网卡、路由表、邻居表、协议栈都是独立的
不管是虚拟机还是容器,当运行在独立的命名空间时,就像是一台单独的主机一样
1.2.需求
下面要通过手工方式创建两个Network Namespace,并最终让它们相互连通,即可以通过 ping 命令测试成功,以使大家能够理解 Docker 网络的底层原理

1.3. 手工实现网络空间
(1).创建两个命名空间
分别创建两个命名空间 ns1 与 ns2
[root@docker ~]# ip netns add ns1
[root@docker ~]#
[root@docker ~]# ip netns add ns2
[root@docker ~]#
[root@docker ~]# ip netns list

因为每个网络空间都是独立的,所以每个 Network Namespace 都具有一个回环网络适配器 lo
[root@docker ~]# ip netns exec ns1 ip a
[root@docker ~]# ip netns exec ns2 ip a

(2).创建网络接口
如果要让两个命名空间连通,则需要用到虚拟设备接口技术 veth pair
该技术需要一对网络接口分别置于两个命名空间中
以下命令用于创建一对网络接口 veth-ns1 与 veth-ns2
ip link add veth-ns1 type veth peer name veth-ns2

此时通过 ip link 查看当前的网络地址情况,可以看到新增了两个相互连通的 veth pair,它们都具有MAC 地址,但它们的状态都是 DOWN,且都不具有 IP
ip link

(3).命名空间添加 veth 接口
通过 ip link set 命令,将这两个网络接口分别分配给两个命名空间
ip link set veth-ns1 netns ns1
ip link set veth-ns2 netns ns2

此时分别在两个命名空间中执行 ip link 命令,可以查看到它们中分别新增了前面指定的一个网络接口
ip netns exec ns1 ip link
ip netns exec ns2 ip link

此时再在主机中查看 ip link,发现原来的那两个网络接口已经消失了

(4).为 veth 接口分配 IP
前面创建的两个网络接口是没有 IP 的
下面要通过 ip netns exec 命令,为每个指定的命名空间执行 IP 添加命令 ip addr add [ip] dev [网络接口]
- 为 ns1 的 veth-ns1 网络接口分配的 IP 为 192.168.1.1,掩码为 24
- 为 ns2 的 veth-ns2 网络接口分配的 IP 为 192.168.1.2,掩码为 24
ip netns exec ns1 ip addr add 192.168.1.1/24 dev veth-ns1
ip netns exec ns2 ip addr add 192.168.1.2/24 dev veth-ns2

此时通过在 ns1 与 ns2 中运行 ip a 命令,便可看到为接口分配的 IP 了
ip netns exec ns1 ip a
ip netns exec ns2 ip a

(5).启动veth 接口
以上两个命名空间中的 veth 接口已经具有了 IP,但其状态仍为 DOWN,还没有开启
下面要通过 ip link set dev [接口] up 来启动指定的网络接口
ip netns exec ns1 ip link set dev veth-ns1 up
ip netns exec ns2 ip link set dev veth-ns2 up

此时再通过 ip a 命令查看两接口的状态,已经变为了 UP
ip netns exec ns1 ip a
ip netns exec ns2 ip a

(6).相互 ping
此时可以通过在两个命名空间中执行 ping 命令来与对方进行连通性测试了
ip netns exec ns1 ping 192.168.1.2
ip netns exec ns2 ping 192.168.1.1

2.网络架构

Docker 网络架构由三个主要部分构成
- CNM
- Libnetwork
- Driver
(1).CNM
CNM(Container Network Model)容器网络模型是一种网络连接的解决方案,是一种设计规范、设计标准,其规定了 Docker 网络的基础组成要素
CNM 中定义了三个基本要素
-
沙盒 Sandbox
一个独立的网络栈
其中包括以太网接口、端口号、路由表、DNS 配置等
Linux Network Namespace 是沙盒的标准实现
-
终端 Endpoint
虚拟网络接口
主要负责创建连接(即将沙盒连接到网络上)
一个终端只能接入某一个网络
-
网络Network
802.1d 网桥的软件实现,是需要交互的终端的集合
(2).Libnetwork
CNM 是设计规范,而 Libnetwork 是开源的、由 Go 语言编写的、跨平台的 CNM 的标准实现
Libnetwork 除了实现了CNM 的三个组件,还实现了本地服务发现、容器负载均衡、以及网络控制层与管理层功能
(3).Driver

每种不同的网络类型都有对应的不同的底层Driver,这些 Driver 负责在主机上真正实现需要的网络功能(例如创建 veth pair 设备等)
不过无论哪种网络类型,其工作方式都是类似的
通过调用 Docker 引擎的API 发出请求,然后由 Libnetwork 做出框架性的处理,然后将请求转发给相应的Driver
通过 docker network ls 命令可以查看当前主机所连接的网络及网络类型
docker network ls

二.Docker的三种网络
1.bridge网络
bridge 网络也称为单机桥接网络,是 Docker 默认的网络模式
该网络模式只能存在于单个 Docker 主机上,其只能用于连接所在 Docker 主机上的容器
1.1.docker0 网桥
(1).查看docker0网桥
bridge 网络模式中具有一个默认的虚拟网桥 docker0,通过 ip a 或 ifconfig 命令都可查看到
ip a

ifconfig

当然通过docker network inspect bridge 也可以查看到网络名称为bridge 的网络的详情
docker network inspect bridge

可以看到该网络的驱动为 bridge,其网桥名称为 docker0
只不过目前该网络上还没有连接任何容器
(2).docker0 网桥工作原理
在 Linux 主机上,Docker 的 bridge 网络由 Bridge 驱动创建,其在创建时会创建一个默认的网桥 docker0
容器与网桥间是通过 veth pair 技术实现的连接,网桥与外网间是通过"网络地址转换NAT 技术"实现的连接,即将通信的数据包中的内网地址转换为外网地址
Bridge 驱动的底层是基于 Linux 内核的 Linux Bridge 技术,该技术已经经历了近 20 年的考验,这就意味着该模式是高性能且非常稳定的

1.2.查看网络连接详情
(1).创建容器1与容器2
-
创建容器1
docker run --name bb1 -it busybox
-
创建容器2
docker run --name bb2 -it busybox
(2).查看 bridge 网络整体连接
通过 docker network inspect 命令查看当前 bridge 网络的整体连接情况
docker network inspect bridge

在 Containers 中可以查看到当前名称为 bridge 的网络中连接的 bb1与 bb2两个容器
这两个容器及宿主机其实就是三个完全独立的 Network Namespace
(3).查看宿主机接口
此时在宿主机上通过 ip a 命令查看当前主机的网络接口情况
ip a

发现除了回环地址 lo、本地网卡 ens33、网桥 docker0 外,还有其它veth 网络接口
这几个veth 就是由 Libnetwork 生成的 veth pair 中的宿主机中的 EndPoint
-
62: veth0aa4653@if61:
表示这是第62个接口,其用于连接外部的第61个接口
-
64: veth5e1bf71@if63:
表示这是第64个接口,其用于连接外部的第63个接口
-
…
(4).查看容器接口
docker exec bb1 ip a
docker exec bb2 ip a

在两个容器中分别使用 ip a 命令查看它们的地址情况,可以看到均包含eth0 的接口
- bb1 中的接口61,即eth0@if62,其用于连接宿主机的第62个接口
- bb2 中的接口63,即eth0@if64,其用于连接宿主机的第 64个接口
它们的接口正好与宿主机中的接口构成两对 pair
(5).查看网桥连接
这里要使用一个专门用于网桥控制管理的命令 brctl
由于该命令默认在 Linux 中没有安装,所以需要首先安装一个网桥的工具包 bridge-utils
yum -y install bridge-utils

使用 brctl show 命令可以查看本机当前所有网桥及其连接情况
可以看到当前宿主机中有一个网桥 docker0,其上连接着两 vethxxx 的接口,就是前面连接 bb1 与 bb2 上两个 eth0 的两个接口
brctl show

可以看到,当前宿主机中docker0网桥,其上连接着几个 vethxxx 的接口
(6).查看容器详情
通过 docker inspect 查看容器的详情,可以看到其网络连接中的网关Geteway 的 IP 地址就是 docker0 网桥的地址
docker inspect bb1


1.3.创建bridge网络
1.3.1.网络创建

(1).创建网络
通过 docker network create 命令可以创建指定名称与类型的网络
docker network create -d bridge bridge2

-
-d 选项用于指定要创建网络时所使用的驱动,即创建的网络类型
-
bridge2 则是新创建网络的名称
(2).查看宿主机支持网络
此时通过 docker network ls 可查看到新创建的网络
docker network ls

(3).查看宿主机网桥
通过 brctl show 命令可以查看到新增了一个网桥,只不过该网桥暂时还没有任何连接的网络接口
该网桥就是在创建新的网络时自动创建的
brctl show

1.3.2.创建容器指定网络
(1).创建容器3
创建一个新的 BusyBox 容器 bb3,其连接在新建的 bridge2 网络上
docker run -d --name bb3 --network bridge2 busybox /bin/sh -c "while true;do sleep 3600;done"
在创建容器时通过–network 指定要连接到的网络,如果不指定则默认连接到默认的bridge 网络

(2).查看新建网络详情
此时查看 bridge2 的网络详情,可以看到容器 bb3 已经连接到了上面
docker network inspect bridge2

(3).查看宿主机网络接口
此时查看当前宿主机的网络接口情况,发现多出了两个接口
一个是 65号接口,其为网桥 br-xxx
一个是 67号接口,其是连接 bb3 的接口 veth774907a@if66
ip a

(4).查看新增容器网络接口
此时查看容器 bb3 的网络接口,发现其66号接口正好是宿主机67号接口的 pair 接口
docker exec bb3 ip a

(5).查看宿主机网桥
此时再查看网桥情况,发现新增网桥上增加了一个接口,而该接口正好就是宿主机上的67号接口
并且该接口的 IP 为 172.19.xx.xx/16,与 bridge 网络 172.17.xx.xx/16 不是同一网段,所以它们之间是不能相互通信的

1.3.3.容器连接到指定网络
(1).连接到指定网络
现在要将容器 bb2 连接到新建的 bridge2 网络上
可以使用 docker network connect 命令
docker network connect bridge2 bb2

(2).查看两个网络详情
此时查看 bridge2 的网络详情中的容器情况,发现 bb2 与 bb3 都在该网络上
docker network inspect bridge2

然后再查看原来的 bridge 网络详情的容器情况,发现 bb2 仍连接在其上(即bb2 容器同时连接在了两个网络上)
docker network inspect bridge

(3).查看容器接口
此时查看 bb2 的网络接口情况,发现其同时具有两个网络接口,分别连接在两个不同的网络上
docker exec bb2 ip a

(4).查看容器详情
查看 bb2 容器详情,可以看到其连接在两个网络上,具有两个 IP
docker inspect bb2

(5).互相ping
容器IP如下
-
bb1
172.17.0.2
-
bb2
172.19.0.3
172.17.0.3
-
bb3
172.19.0.2
容器 bb2 与 bb3 互 ping 是可以 ping 通的
docker exec bb2 ping 172.19.0.2

容器 bb3与 bb2互 ping 是可以 ping 通的
docker exec bb3 ping 172.19.0.3

但 bb3 要 ping 容器 bb2 的另一网段的 IP 是 ping 不通的

(6).容器互ping容器名
除了可以直接 ping 通指定的 IP 外,还可以直接去 ping 对方的容器名称
该方式在生产中非常重要
因为生产中容器的 IP 可能会发生变化,但容器名称一般是不会变的
如果某服务总是直接通过 IP 与容器相连接,那么一旦容器 IP 变化,则该服务将连接不上容器;但如果是通过容器名称相连接的,那么无论容器 IP 如何变化,都将不影响服务与容器的连接
docker exec bb2 ping bb3
docker exec bb3 ping bb2

(7).创建定向链接容器
对于自定义的 bridge 网络,其具有一个特性:该网络上的容器可以通过容器名互 ping
但默认的 bridge 网络是不行的
如果在默认的 bridge 网络上实现通过容器名进行的连接,则需要创建容器时通过–link 选项指定
docker run -d --name bb4 --link bb1 busybox /bin/sh -c "while true;do sleep 3600;done"

此时容器 bb4 直接通过 bb1 的容器名称就是连接上 bb1
docker exec bb4 ping bb1

但容器 bb4 是无法通过容器名称来连接 bb2 的,然后 bb1 也无法通过容器名称连接 bb4
docker exec bb4 ping bb2
docker exec bb1 ping bb4

所以–link 指定的连接是一种定向连接,是带有指向性与方向性的
(8).创建共享网络命名空间容器
在创建容器时可以指定其与某已经存在的容器共享Network Namespace,但要求该已经存在的容器采用的是 bridge 网络模式
docker run -d --name bb1-1 --network container:bb1 busybox /bin/sh -c "while true;do sleep 3600;done"

上面的命令创建了一个 bb1-1 的容器,其共享了 bb1 容器的 Network Namespace
查看两个容器的接口情况,发现完全相同
docker exec bb1-1 ip a
docker exec bb1 ip a

查看容器 bb1-1 的详情,可以发现其没有自身的网络设置,因为其共享的 bb1 容器的网络设置
docker inspect bb1-1

2.none网络
none 网络即没有网络
容器仍是一个独立的 Network Namespace,但没有网络接口,没有 IP
(1).创建none 网络容器
在 docker run 命令中,通过–network none 选项指定创建的容器没有网络功能
docker run -d --name bb5 --network none busybox /bin/sh -c "while true;do sleep 3600;done"

(2).查看容器详情
通过 docker inspect 命令查看该容器的详情,发现其没有 IP,没有网关,没有 MAC 地址
docker inspect bb5

(3).查看容器网络接口
通过 ip a 命令查看容器的网络接口,发现其只有一个回环地址 lo,没有其它接口
docker exec bb5 ip a

3.host网络
host 网络,即与宿主机 host 共用一个 Network Namespace
该网络类型的容器没有独立的网络空间,没有独立的 IP,全部与 host 共用
(1).创建host 网络容器
在 docker run 命令中,通过–network host 选项指定创建的容器为 host 网络
docker run -d --name bb6 --network host busybox /bin/sh -c "while true;do sleep 3600;done"

(2).查看网络详情
通过 docker network inspect host 命令查看网络详情,发现容器 bb6 连接在该网络上,但容器 bb6 却没有 IP、MAC,并且该网络模式中居然没有网关 Gateway
因为该网络模式实际相当于没有网络,容器与宿主机共用 Network Namespace,根本就不需要网络连接
docker network inspect host

(3).查看host 与容器网络接口
通过 ip a 与 docker exec bb6 ip a 命令分别查看宿主机与容器 bb6 的网络接口,发现是一样的
因为它们共用一个Network Namespace,所以也就共用了所有网络接口
docker inspect bb6

(4).关于端口映射
由于容器与宿主机共用一个 Network Namespace,所以无论是 IP 还是应用程序的 Port,容器与宿主机的都是相同的,所以对于容器中应用程序的 Port 不存在映射的问题,host 中的 Port 与容器中的 Port 相同
docker run --name mytomcat --network host -dp 8081:8080 tomcat:8.5.49

上面的tomcat 容器由于指定了网络模式为host,在启动时指定的端口映射不会起作用,系统给出的WARNING 指出,当使用 host 网络模式时,已发布的端口号被丢弃
此时,通过仍需通过 8080 端口访问
http://192.168.10.11:8080/
也正因为 host 与容器中的应用使用的是相同的端口号,所以当采用 host 网络模式时,在一个宿主机中只能启动一个应用的一个容器,否则会出现端口号冲突问题
三.外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射
1、映射端口
1.1.-P随机端口映射
当使用 -P 标记时,Docker会将容器内开放的端口随机的映射到主机的一个端口上
使用 docker ps 可以看到,本地主机的 32769 被映射到了容器的 8080 端口,此时访问本机的 32769端口即可访问容器内 tomcat 应用提供的界面
示例如下:
docker run -d -P tomcat
docker ps

[root@docker ~]# docker exec -it ce6a030be74d /bin/bash
root@ce6a030be74d:/usr/local/tomcat# ll
root@ce6a030be74d:/usr/local/tomcat# cp -r webapps.dist/* webapps

访问容器: http://192.168.1.11:32769/

可以访问成功
同样的,可以通过 docker logs 命令来查看应用的信息
docker logs ce6a030be74d

1.2.-p指定端口映射
-p(小写的)则可以指定要映射的端口
并且在一个指定端口上只可以绑定一个容器
支持的格式有
- ip:hostPort:containerPort
- ip::containerPort
- hostPort:containerPort
注意
- -p 标记可以多次使用来绑定多个端口
示例
docker run -it -d -p 8888:8080 tomcat:8.5.49

(1).映射所有接口地址
-
格式
HOSTPORT:CONTAINERPORT -
含义
未指定ip、指定宿主机port、指定容器port
适用于将容器指定端口指定映射到宿主机的一个端口上(映射所有接口地址)
该操作默认会绑定本地所有接口上的所有地址
-
示例
下载镜像
docker pull centos:7 docker images
启动容器
docker run -itd -p 8000:80 docker.io/centos:7 /bin/bash
(2).映射到指定地址的指定端口
- 格式
IP:HOSTPORT:CONTAINERPORT
- 含义
指定ip、指定宿主机port、指定容器port
适用于映射到指定地址的指定端口
-
示例
将容器的5000端口映射到指定地址127.0.0.1的5000端口上:
docker run -it -d -p 127.0.0.1:5000:5000 docker.io/centos:7 /bin/bash
(3).映射到指定地址的任意端口
-
格式
IP::CONTAINERPORT -
含义
指定ip、未指定宿主机port(随机)、指定容器port
适用于映射到指定地址的任意端口
本地主机会自动分配一个端口映射到容器的开放端口上
-
示例
将容器的4000端口映射到127.0.0.1的任意端口上
docker run -it -d -p 127.0.0.1::4000 docker.io/centos:7 /bin/bash
会将容器的ip127.0.0.1和4000端口,随机映射到宿主机的一个端口上
2.查看端口映射
使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址
【示例】
[root@docker ~]# docker port 57019a8034df
4000/tcp -> 127.0.0.1:32768

更多推荐

所有评论(0)