docker 网络(单机环境)

news/2024/6/3 19:15:41 标签: docker, 网络, 运维, 容器

文章目录

深入理解 Namespace

什么是Namespace

  1. 先来看看那种比较正式的定义。Namespace是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一种资源的使用不会互相干扰。

  2. 这样的解释可能不清楚。举个例子:在Linux系统上,你想要改变系统的主机名,这个主机名就是一个内核的全局资源。但是内核通过实现UTS Namespace,可以将不同的进程分隔在不同的UTS Namespace中,在某个Namespace修改主机名时,另一个Namespace的主机名还是保持不变。

  3. 所以说Namespace是用来隔离进程对系统资源的访问。每一个 Namespace 都有一套自己的系统资源(例如进程ID、主机名、网络接口等),进程只能看到和操作同一个 Namespace 中的资源。这样就可以在逻辑上隔离不同的进程,让它们在各自的 “空间” 中运行,互不干扰。

  4. 在 Linux 系统中,每个进程都与一组 Namespace 关联。这些 Namespace 决定了进程可以看到和影响哪些系统资源。例如,进程的网络 Namespace 决定了进程可以看到和使用哪些网络接口。

  5. 当一个进程被创建时,它会继承其父进程所在的所有 Namespace。但是,也可以在创建新进程时指定其所在的 Namespace,或者将已有的进程移动到新的Namespace。在 Linux 的 /proc 文件系统中,可以查看进程的 Namespace 信息。例如,/proc/[pid]/ns/ 目录下的每个文件都代表了一个 Namespace,这些文件是该进程所在 Namespace 的符号链接。通过查看和比较这些文件,可以确定进程的 Namespace 信息。

image-20230914194056001

看完上面5段话,对于Namespace就会有一个基本的认识。

Namespace当中的 Network Namespace

目前Linux内核总共实现了6种 Namespace。

  • IPC:隔离System V IPC和 POSIX消息队列。
  • Network:隔离网络资源。
  • Mount:隔离文件系统挂载点。
  • PID:隔离进程ID。
  • UTS:隔离主机名和域名。
  • User:隔离用户ID和组ID。

Network Namespace 对网络相关的系统资源进行隔离,每个Network Namespace都有自己的网络设备、IP地址、路由表、/proc/net目录、端口号等。网络隔离的必要性是很明显的举一个例子,在没有隔离的情况下,如果两个不同的容器都想运行同一个Web应用,而这个应用又需要使用80端口,那就会有冲突了。

Libcontainer

Libnetwork是由Go语⾔编写的一个开源工具,该工具具有跨平台性,主要处理Docker网络相关的工作。下图是Libnetwork的整体结构。

image-20230914205054633
  • 沙盒:沙盒是一个隔离的网络运行环境,保存了容器网络栈的配置,包括了对网络接口、路由表和 DNS配置的管理。在 Linux平台上,沙盒是用Linux NetworkNamespace实现的。一个沙盒可以包括来自多个网络的多个Endpoint(网络接口)。
  • 网络接口:Endpoint(网络接口)将沙盒加入一个网络,Endpoint 的实现可以是一对 veth pair或者OVS内部端口,当前的Libnetwork 使用的是veth pair。一个 Endpoint 只能属于一个沙盒及一个网络。通过给沙盒增加多个Endpoint可以将一个沙盒加入多个网络
  • 网络网络包括一组能互相通信的Endpoint。网络的实现可以是bridge ,host,none等。
  • 可拔插接口:可拔插接口指的是允许开发者将自定义的网络驱动接入到 Libnetwork 中,使得 Docker 容器可以使用这些自定义的网络驱动进行网络通信。这种接口的设计使得 Libnetwork 具备了极高的灵活性和可扩展性。
  • 服务发现:Libnetwork 的网络控制层和管理层负责创建和管理网络以及网络接口。这些网络接口可以被绑定Docker 容器上,使得这些容器可以在同一个网络中相互通信。通过这种方式,容器可以实现本地服务发现,即在同一个网络中的容器可以通过容器名称或者其他标识来找到其他容器,从而实现相互通信。
  • 负载均衡:Libnetwork 的网络控制层和管理层可以创建和管理网络,这些网络可以配置为支持负载均衡。例如,可以使用 Overlay 网络驱动创建一个跨多个 Docker 宿主机的虚拟网络,然后在这个虚拟网络中的容器之间实现负载均衡。另外,Libnetwork 还可以与 Docker Swarm 集群管理工具集成,通过 Docker Swarm,可以实现在集群范围内的容器负载均衡。

docker__45">docker 网络基础

有了上面的一些基础知识做铺垫,理解docker 网络的底层原理可能会轻松一点。下面就用一些linux命令创建两个命名空间,最后让这两个命名空间之间能相互通信。

创建两个命名空间

分别创建两个命名空间 namespace1 与 namespace2。
image-20230914212514298

因为每个网络空间都是独立的,所以每个 Network Namespace 都具有一个回环网络适配器 lo。可以看到这个接口的最大传输单元(MTU)是65536字节,其中MTU是网络接口可以接受的最大数据包大小。并且还可以看到state DOWN表示这个接口目前没有启用。而qlen 1000则表示这个接口的发送队列的长度,即接口可以缓存的待发送数据包的数量。
image-20230914212645538

创建网络接口 veth pair

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

以下命令用于创建一对网络接口 veth-ns1 与 veth-ns2。
image-20230914214137570

对于ip link add veth-ns1 type veth peer name veth-ns2 这个命令的解释如下:

  • ip link add:这是用于创建网络设备的命令。
  • veth-ns1:这是你要创建的第一个veth设备的名称。
  • type veth:这表示你要创建的设备的类型是 veth。
  • peer name veth-ns2:这表示你要创建的第二个veth设备的名称。peer关键字表示这两个设备是一对,互为对方的端点。

而 ip link show veth-ns1命令和 ip link show veth-ns2 命令展示了两个虚拟网络接口的信息。通过 veth-ns1@veth-ns2 和 veth-ns2@veth-ns1 可以发现这两个网络接口是一对接口。除此之外,还能看到网络接口的状态和MAC地址等等信息。

命名空间添加 veth 接口

通过 ip link set 命令,将这两个网络接口分别分配给两个命名空间。
image-20230914214853868

为 veth 接口分配 IP

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

启动 veth 接口

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

相互 ping

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

bridge 网络

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

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

搭建网络环境

需求:搭建如下的网络环境。
image-20230915101209888

docker0__105">查看docker0 网桥

image-20230915102335813
  1. 网络接口名称(docker0)及其状态(UP,表示启动并运行)。
  2. docker0 的 MAC 地址(02:42:36:20:cc:8b)。
  3. docker0 的 IP 地址(172.17.0.1)和子网掩码(/16,表示子网的地址范围是 172.17.0.0 到 172.17.255.255)。
  4. docker0 的广播地址(172.17.255.255)。
  5. docker0 的 IPv6 地址(fe80::42:36ff:fe20:cc8b/64)。
  6. docker0 的 MTU(Maximum Transmission Unit,最大传输单元)是 1500。这是 Ethernet 的标准 MTU。

创建网桥 bridge2

image-20230915103033257

-d 选项用于指定要创建网络时所使用的驱动,即创建的网络类型。最后的 bridge2 则是新创建网络的名称。查看bridge2网桥的相关信息:

image-20230915111942451

可以看到bridge2网桥的IP地址为172.18.0.1。

创建容器并连接网络

创建busybox1容器并连接bridge网桥:--network bridge 告诉 Docker 使用 bridge 网桥来运行 busybox1 容器
image-20230915111648319

可以看到busybox1的IP地址为172.17.0.2。现在创建busybox2容器并连接bridge网桥。
image-20230915112458290

可以看到busybox2容器的IP地址为172.17.0.3。现在要将busybox2连接到bridge2网桥上。
image-20230915112959629

使用docker network connect命令就可以让busybox2容器连接到bridge2网桥上。可以发现busybox2的IP地址又多了一个172.18.0.2/16。说明这个IP地址在172.18.0.0这个网段上,也就是bridge2网桥所在的网段。现在创建busybox3容器并连接到bridge2网桥上。
image-20230915113535516

可以看到busybox3的IP地址为172.18.0.3。

查看容器详情

这里以busybox2容器为例,查看该容器网络详情。

docker inspect busybox2

# 查看容器网络配置信息:NetworkSettings
{
    "Bridge": "", 
    "SandboxID": "145b13df0a94364eda70a3dd93a10b171f23159ddff200313f4a0c558505b9e6", 
    "HairpinMode": false, 
    "LinkLocalIPv6Address": "", 
    "LinkLocalIPv6PrefixLen": 0, 
    "Ports": { }, 
    "SandboxKey": "/var/run/docker/netns/145b13df0a94", 
    "SecondaryIPAddresses": null, 
    "SecondaryIPv6Addresses": null, 
    "EndpointID": "2af54e966620633d28dfc91e54816e4a85a4c105c0213a7ef41d2c9fdcf2f3df", 
    "Gateway": "172.17.0.1", 
    "GlobalIPv6Address": "", 
    "GlobalIPv6PrefixLen": 0, 
    "IPAddress": "172.17.0.3", 
    "IPPrefixLen": 16, 
    "IPv6Gateway": "", 
    "MacAddress": "02:42:ac:11:00:03", 
    "Networks": {
        "bridge": {
            "IPAMConfig": null, 
            "Links": null, 
            "Aliases": null, 
            "NetworkID": "5f417d52f8fdae77a94202c473b03e1998de09f7509363e03826c01a3f669f14", 
            "EndpointID": "2af54e966620633d28dfc91e54816e4a85a4c105c0213a7ef41d2c9fdcf2f3df", 
            "Gateway": "172.17.0.1", 
            "IPAddress": "172.17.0.3", 
            "IPPrefixLen": 16, 
            "IPv6Gateway": "", 
            "GlobalIPv6Address": "", 
            "GlobalIPv6PrefixLen": 0, 
            "MacAddress": "02:42:ac:11:00:03", 
            "DriverOpts": null
        }, 
        "bridge2": {
            "IPAMConfig": { }, 
            "Links": null, 
            "Aliases": [
                "8be8f43ccd8d"
            ], 
            "NetworkID": "5f4893ee055e6a11841ff89b5a6b8d088d8d80362deac9f4c1ff0ee9d6974b96", 
            "EndpointID": "c29ec9f1b1a75010c70a5f908175101bcbfc21b0159b3475fe7d7e50f86c3741", 
            "Gateway": "172.18.0.1", 
            "IPAddress": "172.18.0.2", 
            "IPPrefixLen": 16, 
            "IPv6Gateway": "", 
            "GlobalIPv6Address": "", 
            "GlobalIPv6PrefixLen": 0, 
            "MacAddress": "02:42:ac:12:00:02", 
            "DriverOpts": { }
        }
    }
}

可以看到busybox2这个容器有两个网段,分别是172.17.0.1和172.18.0.1;并且busybox2这个容器有两个IP地址,分别是172.17.0.3和172.18.0.2。

查看网络详情

# 查看网桥的相关信息
docker network inspect bridge2

"Containers": {
        "8be8f43ccd8d1177bab90f81f3499f2448bfdc046c06db298f3e39f3943a5147": {
            "Name": "busybox2",
            "EndpointID": "a7ecc7cf1092e7c7601ac14b560a43b648cde38d02ffe770ba9ec77a33b0de95",
            "MacAddress": "02:42:ac:12:00:02",
            "IPv4Address": "172.18.0.2/16",
            "IPv6Address": ""
        },
        "97cbf3344e7b5587ce84ac0141af9a4b40692dd14407fc2ac40f20bf5f02456c": {
            "Name": "busybox3",
            "EndpointID": "29cc4737c14c54b1b8a4698c66faa833e6262b4163152ee50b3ef6c7969228c0",
            "MacAddress": "02:42:ac:12:00:03",
            "IPv4Address": "172.18.0.3/16",
            "IPv6Address": ""
        }
    }

查看 bridge2 的网络详情中的容器情况,发现 busybox2 与 busybox3 都在该网络上。

容器之间相互ping

image-20230915141611179

发现busybox1能ping通busybox2;busybox2能Ping通busybox3;而busybox1不能ping通busybox3。说明只有在同一段网络下的容器之间才能相互ping通。

ping 容器

image-20230915152009127

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

创建定向连接容器

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

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

image-20230915153308134

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

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

docker run -it --name busybox-1 --network container:busybox1 busybox /bin/sh

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

image-20230915153824101

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

none 网络

none 网络,即没有网络容器仍是一个独立的 Network Namespace,但没有网络接口,没有 IP。

创建 none 网络容器

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

docker run -it --name busybox5 --network none busybox /bin/sh

查看容器详情

# 查看容器详情的命令
docker inspect busybox5

# 下面是busybox5关于网络部分的信息
"NetworkSettings": {
    "Bridge": "",
    "SandboxID": "400b397e12ca82bc791f5fd4d194a05289445e489a121e2fce06ca54817f2f86",
    "HairpinMode": false,
    "LinkLocalIPv6Address": "",
    "LinkLocalIPv6PrefixLen": 0,
    "Ports": {

    },
    "SandboxKey": "/var/run/docker/netns/400b397e12ca",
    "SecondaryIPAddresses": null,
    "SecondaryIPv6Addresses": null,
    "EndpointID": "",
    "Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "IPAddress": "",
    "IPPrefixLen": 0,
    "IPv6Gateway": "",
    "MacAddress": "",
    "Networks": {
    "none": {
      "IPAMConfig": null,
      "Links": null,
      "Aliases": null,
      "NetworkID": "3b0eaed4d1d8ff72e62cc883d3a97639284fbd8eec96d6919322acbb4acd8d17",
      "EndpointID": "61ed43896cfc51adf35120c16f335ba58dcb124103cb0bb6f17b7b9eee2ca355",
      "Gateway": "",
      "IPAddress": "",
      "IPPrefixLen": 0,
      "IPv6Gateway": "",
      "GlobalIPv6Address": "",
      "GlobalIPv6PrefixLen": 0,
      "MacAddress": "",
      "DriverOpts": null
    	}
    }
}

通过 docker inspect 命令查看该容器的详情,发现其没有 IP,没有网关,没有 MAC 地址。这种none网络的主要用途是为那些不需要或不希望有任何网络通信功能的容器提供一个安全的运行环境,例如一些只需要进行本地计算或处理本地数据的应用。

host 网络

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

创建 host 网络容器

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

docker run -it --name busybox6 --network host busybox /bin/sh

查看容器详情

# 查看容器详情的命令
docker inspect busybox6

# 下面是busybox5关于网络部分的信息
"NetworkSettings": {
    "Bridge": "",
    "SandboxID": "d16a68fa18c745642fe4a7833e89bb2ee7351c06291cb5441dc3c35f7c350321",
    "HairpinMode": false,
    "LinkLocalIPv6Address": "",
    "LinkLocalIPv6PrefixLen": 0,
    "Ports": {

    },
    "SandboxKey": "/var/run/docker/netns/default",
    "SecondaryIPAddresses": null,
    "SecondaryIPv6Addresses": null,
    "EndpointID": "",
    "Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "IPAddress": "",
    "IPPrefixLen": 0,
    "IPv6Gateway": "",
    "MacAddress": "",
    "Networks": {
    "host": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "16501fad09abfb197b94593aa27568c6c91cfbebb2c521553da481552fa3ad1f",
        "EndpointID": "7cdf57ebf08f15fe7069b7f03f46a711b6b283ae8aff85ed614b6b5524dc9035",
        "Gateway": "",
        "IPAddress": "",
        "IPPrefixLen": 0,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "",
        "DriverOpts": null
        }
    }
}

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

查看容器的IP信息

通过 docker exec busybox6 ip addr 命令查看容器的IP信息可以发现该容器的IP与宿主机的IP信息一模一样。所以在host模式下,容器直接使用宿主机的网络接口、IP和路由规则。这意味着在host网络模式下运行的容器可以直接监听宿主机上的所有网络端口,也正是因为容器与宿主机共用网络端口,所以在host模式下的运行容器不需要进行端口映射就能直接对外提供服务。

这种模式的主要用途是为那些需要直接访问宿主机网络环境或者需要高性能网络通信的容器提供一个高效的运行环境。但是,由于它会让容器直接暴露在宿主机的网络环境中,所以在某些需要隔离或安全的场景中可能不适用。


http://www.niftyadmin.cn/n/5035380.html

相关文章

删除您和Bard的对话记录

如果您想删除您和Bard的对话记录,可以通过以下步骤操作: 前往Bard网站或应用程序。https://myactivity.google.com/product/bard?otzr1点击左下角的“删除”下拉框。 您可以选择删除所有对话记录、过去一小时或过去一天的对话记录、特定时间段的对话记…

线程池各个参数设置说明

1. corePoolSize 核心线程数 看处理业务属于IO密集型还是属于cpu密集型IO密集型: 通常设置为N1,还有一个计算公式:线程数 cpu数*(线程等待时间/线程总的处理时间) 但是由于服务器除了这个服务可能还部署有其他服务,…

SpringMVC----自定义注解

目录 自定义注解 是什么 作用 JDK元注解 测试案列 案例一(获取类与方法上的注解值) 案例二(获取类属性上的注解属性值) 案例三(获取参数修饰注解对应的属性值) 五.Aop自定义注解的应用 Mylog…

笔记 | 非素数个数(朴素筛查 || 埃式筛查法)

非素数个数 题目描述朴素筛查方法题解 题目描述 求a-b之间的非素数个数 特别的&#xff0c;1也算作素数&#xff0c;区间是[a, b]。 输入输出格式 输入描述: 多组测试数据。 输入两个正整数数a,b&#xff0c;其中a<b<10^7。 输出描述: 输出答案。 输入输出样例 输入样例…

达摩院SPACE对话大模型:预训练语言模型,预训练对话模型,知识注入

01 预训练语言模型 VS 预训练对话模型 1. 大规模语言模型 过去几年 NLP 领域的重大进展&#xff0c;主要是大型预训练模型出现与大规模使用。预训练语言模型有了很大的发展&#xff0c;出现了很多变种。但是&#xff0c;本质上都还是语言模型&#xff0c;如上图右边的流程图所…

类模板深度剖析

类模板可以定义任意多个不同的类型参数 类模板可以被特化 可以指定类模板的特定实现 部分类型参数必须显示指定 根据类型参数分开实现类模板 类模板的特化类型 部分特化 - 用特定规则约束类型参数 完全特化 - 完全显示指定类型参数 类模板特化注意事项 特化只是模板的分开…

Python150题day06

1.4字典练习题 ①字典基本操作 dic { python: 95, java: 99, c: 100 } 用程序解答以下题目 1.字典的长度是多少 2.请修改java这个key对应的value值为98 3.删除 c 这个key 4.增加一个key-value对&#xff0c;key值为 php,value是90 5.获取所有的key值&#xff0c;存储在列表里…

如何使用UVM寄存器模型中的callback

文章目录 前言一、底层UVM的介绍二、UVM寄存器模型callback的使用1、拓展2、绑定 总结 前言 我们在使用UVM的寄存器模型过程中&#xff0c;有时候需要在寄存器配置配置前准备一些数据&#xff0c;或者在寄存器配置之后触发一些操作&#xff0c;这个时候就可以用到UVM寄存器模型…