简单的docker学习 第7章 docker网络

第7章 Docker 网络

7.1Docker 网络理论基础

Docker 网络中的相关命令非常少,但需要掌握的底层原理相对较多。

首先使用busybox创建两个容器,方便后续使用

# 之后使用ctrl + p + q 退出,保持后台运行
docker run --name bb1 -it busybox /bin/sh
# 使用脚本让其保持不退出状态
docker run --name bb2 -d busybox /bin/sh -c "while true; do sleep 3600; done"

image-20240711101639886

7.1.1 Network Namespace

Docker 网络的底层原理是 Linux 的 Network Namespace,所以对于 Linux Network Namespace 的理解对 Docker 网络底层原理的理解非常重要。

  • 简介

    Network Namespace 是 Linux 内核提供的用于实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,每个独立的网络空间内的防火墙、网卡、路由表、邻居表、协议栈都是独立的。不管是虚拟机还是容器,当运行在独立的命名空间时,就像是一台单独的主机一样。

  • 需求

    下面要通过手工方式创建两个 Network Namespace,并最终让它们相互连通,即可以通过 ping 命令测试成功。以使大家能够理解 Docker 网络的底层原理。

    image-20240710164703982

  • 创建两个命名空间

    # 分别创建两个命名空间 ns1 与 ns2。
    ip netns add ns1
    ip netns add ns2
    

    image-20240711091929799

    因为每个网络空间都是独立的,所以每个 Network Namespace 都具有一个回环网络适配器 lo

    ip netns exec ns1 ip a
    ip netns exec ns2 ip a
    

    image-20240711092112281

  • 创建网络接口 veth pair

    如果要让两个命名空间连通,则需要用到**虚拟设备接口技术 veth pair**。该技术需要一对网络接口分别置于两个命名空间中。

    # 以下命令用于创建一对网络接口 veth-ns1 与 veth-ns2。
    ip link add veth-ns1 type veth peer name veth-ns2
    

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

    image-20240711092558272

  • 命名空间添加 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
    

    image-20240711093551298

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

    image-20240711093650185

  • veth 接口分配 IP

    前面创建的两个网络接口是没有 IP 的。下面要通过 ip netns exec 命令,为每个指定的命名空间执行 IP 添加命令 ip addr add [ip] dev [网络接口]。

    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
    

    image-20240711093850043

    为 ns1 的 veth-ns1 网络接口分配的 IP 为 192.168.1.1,掩码为 24;为 ns2 的 veth-ns2 网络接口分配的 IP 为 192.168.1.2,掩码为 24。此时通过在 ns1 与 ns2 中运行 ip a 命令,便可看到为接口分配的 IP 了

    ip netns exec ns1 ip a
    ip netns exec ns2 ip a
    

    image-20240711093956186

  • 启动 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
    

    image-20240711094353540

  • 相互 ping

    此时可以通过在两个命名空间中执行 ping 命令来与对方进行连通性测试了。

    ip netns exec ns1 ping 192.168.1.2
    ip netns exec ns2 ping 192.168.1.1
    

    image-20240711094523513

7.1.2 CNM

image-20240711095706908

Docker 网络架构由三个主要部分构成:CNM、Libnetwork 与 Driver。CNM,Container Network Model,容器网络模型,其是一种网络连接的解决方案,是一种设计规范、设计标准,其规定了 Docker 网络的基础组成要素。

CNM 中定义了三个基本要素:沙盒 Sandbox,终端 Endpoint 与网络 Network。

  • 沙盒:一个独立的网络栈,其中包括以太网接口、端口号、路由表、DNS 配置等。Linux Network Namespace 是沙盒的标准实现。

  • 终端:虚拟网络接口,主要负责创建连接,即将沙盒连接到网络上。一个终端只能接入某一个网络。

  • 网络:802.1d 网桥的软件实现,是需要交互的终端的集合。

7.1.3 Libnetwork

CNM 是设计规范,而 Libnetwork 是开源的、由 Go 语言编写的、跨平台的 CNM 的标准实现。

Libnetwork 除了实现了 CNM 的三个组件,还实现了本地服务发现、容器负载均衡,以及网络控制层与管理层功能。

7.1.4 Driver

image-20240711095833878

每种不同的网络类型都有对应的不同的底层 Driver,这些 Driver 负责在主机上真正实现需要的网络功能,例如创建 veth pair 设备等。

不过,无论哪种网络类型,其工作方式都是类似的。通过调用 Docker 引擎的 API 发出请求,然后由 Libnetwork 做出框架性的处理,然后将请求转发给相应的 Driver。

通过 docker network ls 命令可以查看当前主机所连接的网络及网络类型

docker network ls

image-20240711095955387

7.2 bridge 网络

bridge 网络,也称为单机桥接网络,是 Docker 默认的网络模式。该网络模式只能存在于单个 Docker 主机上,其只能用于连接所在 Docker 主机上的容器。

7.2.1 docker0 网桥
  • 查看 docker0 网桥

    bridge 网络模式中具有一个默认的虚拟网桥 docker0,通过 ip a 或 ifconfig 命令都可查看到

    ip a
    ifconfig
    

    image-20240711100148294

    image-20240711100239864

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

    image-20240711100543982

    可以看到该网络的驱动为 bridge,其网桥名称为 docker0。只不过,目前该网络上还没有连接任何容器。

  • docker0 网桥工作原理
    image-20240711100603489

    在 Linux 主机上,Docker 的 bridge 网络由 Bridge 驱动创建,其在创建时会创建一个默认的网桥 docker0。容器与网桥间是通过 veth pair 技术实现的连接,网桥与外网间是通过“网络地址转换 NAT 技术”实现的连接,即将通信的数据包中的内网地址转换为外网地址。

    Bridge 驱动的底层是基于 Linux 内核的 Linux Bridge 技术。该技术已经经历了近 20 年的考验,这就意味着该模式是高性能且非常稳定的。

7.2.2 查看网络连接详情
  • 查看 bridge 网络整体连接

    现在通过 docker network inspect 命令查看当前 bridge 网络的整体连接情况。

    docker network inspect bridge
    

    image-20240711101800025

    在 Containers 中可以查看到当前名称为 bridge 的网络中连接的 bb1 与 bb2 两个容器。这两个容器及宿主机,其实就是三个完全独立的 Network Namespace。

  • 查看宿主机接口

    此时在宿主机上通过 ip a 命令查看当前主机的网络接口情况

    image-20240711102233527

    发现除了回环地址 lo,本地网卡 ens33,网桥 docker0 外,还有两个 veth 网络接口。这两个 veth 就是由 Libnetwork 生成的 veth pair 中的宿主机中的 EndPoint。

    • 7: vethxxx@if6 表示这是第 7 个接口,其用于连接外部的第 6 个接口

    • 11: vethxxx@if10 表示这是第 11 个接口,其用于连接外部的第 10 个接口

  • 查看容器接口

    docker exec bb1 ip a
    docker exec bb2 ip a
    

    image-20240711103029011

    在两个容器中分别使用 ip a 命令查看它们的地址情况,可以看到均包含 eth0 的接口。其中bb1中的接口6,即eth0@if7,其用于连接宿主机的第7个接口;bb2的接口10,即eth0@if11,其用于连接宿主机的第 11 个接口。

    它们的接口正好与宿主机中的接口构成两对 pair。

  • 查看网桥连接

    这里要使用一个专门用于网桥控制管理的命令 brctl。由于该命令默认在 Linux 中没有安装,所以需要首先安装一个网桥的工具包 bridge-utils。

    yum -y install bridge-utils
    

    image-20240711103701476

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

    image-20240711103750643

  • 查看容器详情

    通过 docker inspect 查看容器的详情,可以看到,其网络连接中的网关 Geteway 的 IP 地址就是 docker0 网桥的地址。

    image-20240711104007345

7.2.3 网络创建

image-20240711104034644

  • 创建网络

    通过 docker network create 命令可以创建指定名称与类型的网络。

    # -d 选项用于指定要创建网络时所使用的驱动,即创建的网络类型。最后的 bridge2 则是新创建网络的名称。
    docker network create -d bridge bridge2
    

    image-20240711104146091

  • 查看宿主机支持网络

    此时通过 docker network ls 可查看到新创建的网络。

    docker network ls
    

    image-20240711104309157

  • 查看宿主机网桥

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

    brctl show
    

    image-20240711104458134

7.2.4 创建容器指定网络
  • 创建容器

    现在要创建一个新的 BusyBox 容器 bb3,其连接在新建的 bridge2 网络上。在创建容器时通过–network 指定要连接到的网络,如果不指定,默认连接到默认的bridge 网络。

    docker run --name bb3 --network bridge2 busybox /bin/sh -c "while true; do sleep 3600; done"
    
  • 查看新建网络详情

    # 此时查看 bridge2 的网络详情,可以看到容器 bb3 已经连接到了上面。
    docker network inspect bridge2
    

    image-20240711104922268

  • 查看宿主机网络接口

    查看当前宿主机的网络接口情况,发现多出了两个接口。其中一个是 12 号接口,其为网桥 br-xxx,一个是 14 号接口,其是连接 bb3 的接口 vethxxx@if13

    image-20240711105105442

  • 查看新增容器网络接口

    # 此时查看容器 bb3 的网络接口,发现其 9 号接口正好是宿主机 10 号接口的 pair 接口
    docker exec bb3 ip a
    

    image-20240711110326885

  • 查看宿主机网桥

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

    brctl show
    

    image-20240711110445702

    image-20240711110759499

7.2.5 容器连接到指定网络
  • 连接到指定网络

    现在要将容器 bb2 连接到新建的 bridge2 网络上。可以使用 docker network connect 命令

    docker network connect bridge2 bb2
    
  • 查看两个网络详情

    此时查看 bridge2 的网络详情中的容器情况,发现 bb2 与 bb3 都在该网络上。

    docker network inspect bridge2
    

    image-20240711110927512

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

    docker network inspect bridge
    

    image-20240711111032413

  • 查看容器接口

    此时查看 bb2 的网络接口情况,发现其同时具有两个网络接口,分别连接在两个不同的网络上。

    docker exec bb2 ip a
    

    image-20240711111146687

  • 查看容器详情

    查看 bb2 容器详情,可以看到其连接在两个网络上,具有两个 IP。

    image-20240711111245757

  • 容器互 ping

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

    docker exec bb2 ping 172.18.0.2
    docker exec bb2 ping 172.17.0.2
    

    image-20240711111608904

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

    docker exec bb3 ping 172.17.0.3
    

    image-20240711111952725

  • 容器互 ping 容器名

    除了可以直接 ping 通指定的 IP 外,还可以直接去 ping 对方的容器名称。

    注意: 通过容器名称ping通需要自定义bridge,默认的不可以

    docker exec bb2 ping bb3
    docker exec bb3 ping bb2
    

    image-20240711112354068

    该方式在生产中非常重要。因为生产中容器的 IP 可能会发生变化,但容器名称一般是不会变的。如果某服务总是直接通过 IP 与容器相连接,那么一旦容器 IP 变化,则该服务将连接不上容器。但如果是通过容器名称相连接的,那么无论容器 IP 如何变化,都将不影响服务与容器的连接。

  • 创建定向连接容器

    对于自定义的 bridge 网络,其具有一个特性:该网络上的容器可以通过容器名互 ping。但默认的 bridge 网络是不行的。如果在默认的 bridge 网络上实现通过容器名进行的连接,则需要创建容器时通过–link 选项指定

    docker run --name bb4 -d --link bb1 busybox /bin/sh -c "while true; do sleep 3600; done"
    

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

    docker exec bb4 ping bb1
    

    image-20240711134508777

    但容器 bb4 是无法通过容器名称来连接 bb2 的。然后 bb1 也无法通过容器名称连接 bb4。所以,–link 指定的连接是一种定向连接,是带有指向性与方向性的

  • 创建共享网络命名空间容器

    在创建容器时可以指定其与某已经存在的容器共享 Network Namespace,但要求该已经存在的容器采用的是 bridge 网络模式。

    # 下面的命令创建了一个 bb1-1 的容器,其共享了 bb1 容器的 Network Namespace。查看两个容器的接口情况,发现完全相同。
    docker run -d --name bb1-1 --network container:bb1 busybox /bin/sh -c "while true; do sleep 3600; done"
    

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

    image-20240711135527206

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

    docker inspect bb1-1
    

    image-20240711135628695

7.3 none 网络

在 docker run 命令中,通过–network none 选项指定创建的容器没有网络功能

docker run -d --name bb5 --network none busybox /bin/sh -c "while true; do sleep 3600; done"

image-20240711135816209

7.3.2 查看容器详情

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

docker inspect bb5

image-20240711135943924

7.3.3 查看容器网络接口

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

docker exec bb5 ip a

image-20240711140055929

7.4 host 网络

host 网络,即与宿主机 host 共用一个 Network Namespace。该网络类型的容器没有独立的网络空间,没有独立的 IP,全部与 host 共用。

7.4.1 创建 host 网络容器

在 docker run 命令中,通过–network host 选项指定创建的容器为 host 网络

docker run --name bb6 --network host busybox /bin/sh -c "while true; do sleep 3600; done"
7.4.2 查看网络详情

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

docker network inspect host

image-20240711140641411

7.4.3 查看 host 与容器网络接口

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

docker exec bb6 ip a

image-20240711140924466

image-20240711140945249

7.4.4 关于端口映射

由于容器与宿主机共用一个 Network Namespace,所以无论是 IP 还是应用程序的 Port,容器与宿主机的都是相同的,所以对于容器中应用程序的 Port 不存在映射的问题,host 中的 Port 与容器中的 Port 相同

docker run --name mytomcat --network host -dp 8081:8080 tomcat:8.5.32

image-20240711141221607

上面的tomcat容器由于指定了网络模式为host,在启动时指定的端口映射不会起作用。系统给出的 WARNING 指出,当使用 host 网络模式时,已发布的端口号被丢弃。此时,通过仍需通过 8080 端口访问。

image-20240711142149922

也正因为 host 与容器中的应用使用的是相同的端口号,所以当采用 host 网络模式时,在一个宿主机中只能启动一个应用的一个容器,否则会出现端口号冲突问题。

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值