K8S系列-Kubernetes网络
一、Kubernetes网络模型
Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中,不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是,用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑如何将容器端口映射到主机端口等问题。
实际上,在Kubernetes世界里,IP是以Pod为单位进行分配的。一个Pod内部的所有容器共享一个网络堆栈(相当于一个网络命名空间,它们的地址、网络设备、配置等都是共享的)。按照这个网络原则抽象出来的为每个Pod都设置一个IP地址的模型也被称作IP-per-Pod模型。IP-per-Pod模型是一个简单的兼容性较好的模型。从该模型的网络的端口分配、域名解析、服务发现、负载均衡、应用配置和迁移等角度来看,Pod都能够被看作一台独立的虚拟机或物理机。
由于Kubernetes的网络模型假设Pod之间访问时使用的是对方Pod的实际地址,所以一个Pod内部的应用程序看到的自已的IP地址和端口与集群内其他Pod看到的一样。它们都是Pod实际分配的IP地址。
二、linux网络基础
k8s部署到linux,其网络模型的具体实现是基于linux的,下面我们就来看下linux的网络处理。
2.1、网络命名空间
为了支持网络协议栈的多个实例,Linux在网络栈中引入了网络命名空间,这些独立的协议栈被隔离到不同的命名空间中。处于不同命名空间中的网络栈是完全隔离的,彼此之间无法通信。Docker正是利用了网络的命名空间特性,实现了不同容器之间的网络隔离。
在Linux的网络命名空间中可以有自已独立的路由表及独立的iptables设置来提供包转发、NAT及IP包过滤等功能。
为了隔离出独立的协议栈,需要纳人命名空间的元素有进程、套接字、网络设备等。进程创建的套接字必须属于某个命名空间,套接字的操作也必须在命名空间中进行。
由于网络命名空间代表的是一个独立的协议栈,它们之间是相互隔离的,彼此无法通信。在协议栈内部都看不到对方。我们如果需要让处于不同命名空间中的网络相互通信,基至与外部的网络进行通信呢?就需要应用Veth 设备对。Veth设备对的一个重要作用就是打通了相互看不到的协议栈之间的壁垒,它就像一条管子,一端莲着这个网络命名空间的协议栈,一端连看另一个网络命名空间的协议栈。
2.2、Veth设备对
Veth设备是Virtual Ethernet Device的缩写,即虚拟以太网设备,是Linux系统下的一种虚拟网络接口设备。它总是成对出现,形成veth pair(veth对),可以理解为是用一根虚拟的网线将两台设备(通常是两个命名空间或网络空间)直接连接起来。
[root@node4 feverasa]#
[root@node4 feverasa]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
...............
[root@node4 feverasa]# ip link add veth1 type veth peer name veth2
[root@node4 feverasa]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
..........link/ether 52:54:00:5d:fa:5d brd ff:ff:ff:ff:ff:ff
5: veth2@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 4e:62:41:af:70:84 brd ff:ff:ff:ff:ff:ff
6: veth1@veth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
[root@node4 feverasa]#
这里我们可以看到有一对veth了,veth1其的peer是veth2。现在我们创建两个网络命名空间netns1、netns2,然后将veth1移到netns1、veth2移到netns2。
[root@node4 feverasa]# ip netns add netns1
[root@node4 feverasa]# ip netns add netns2
[root@node4 feverasa]# ip link set veth1 netns netns1
[root@node4 feverasa]# ip link set veth2 netns netns2
[root@node4 feverasa]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000.............
[root@node4 feverasa]# ip netns exec netns1 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth1@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether e6:db:87:c7:64:4f brd ff:ff:ff:ff:ff:ff link-netnsid 1
[root@node4 feverasa]# ip netns exec netns2 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth2@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 4e:62:41:af:70:84 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@node4 feverasa]#
下面我们分别给veth1、veth2分配ip,在启动它们,并ping通其网络。
[root@node4 feverasa]# ip netns exec netns1 ip addr add 192.168.2.1/24 dev veth1
[root@node4 feverasa]# ip netns exec netns2 ip addr add 192.168.2.2/24 dev veth2
[root@node4 feverasa]# ip netns exec netns1 ip link set dev veth1 up
[root@node4 feverasa]# ip netns exec netns2 ip link set dev veth2 up
[root@node4 feverasa]# ip netns exec netns1 ping 192.168.2.2
PING 192.168.2.2 (192.168.2.2) 56(84) bytes of data.
64 bytes from 192.168.2.2: icmp_seq=1 ttl=64 time=0.104 ms
64 bytes from 192.168.2.2: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 192.168.2.2: icmp_seq=3 ttl=64 time=0.069 ms
^C
--- 192.168.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2007ms
rtt min/avg/max/mdev = 0.067/0.080/0.104/0.017 ms
[root@node4 feverasa]#
在 Docker 内部,就是通过 Veth 设备对连通容器与宿主机的网络。
2.2、虚拟网桥
Linux可以支持多个不同的网络,怎样将这些网络连接起来并实现各网络中主机的相互通信呢,就可以使用用网桥。网桥是一个二层的虚拟网络设备,把若干个网络接口“连接”起来,以使得网络接口之间的报文能够相互转发。网桥能够解析收发的报文,读取目标MAC地址的信息,将其与自已记录的MAC表结合,来决策报文的转发目标网络接口。为了实现这些功能,网桥会学习源MAC地址(二层网桥转发的依据就是MAC地址)。在转发报文时,网桥只需向特定的网口进行转发,来避免不必要的网络交互。如果它遇到一个自已从未学习到的地址,就无法知道这个报文应该向哪个网络接口转发,将报文广播给所有的网络接口。
同时,当我们给网桥分配一个ip地址后,其也可以作用于第三层也就是网络层,也就是判断当前的数据包是发送给当前子网内部中,还是发到给其他的网络。
2.3、容器 Bridge网络
当我们使用Bridge网络模式,也就是直接使用宿主机的 IP 地址与外界进行通信,就是上面这种网络连接,通过宿主机的物理网卡eth0与外面的网络进行连接,而宿主机里面的各个容器实例之间,则通过容器网桥br0进行连接。
1、网络veth
[root@k8s-node1 feverasa]# docker run -d spring_docker_test:0.0.7 /bin/bash
6831bc2ad0801649a0350777cc299c51a4fb59dcea54678a693c2533f84b188f
[root@k8s-node1 feverasa]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 6831bc2ad0801649a0350777cc299c51a4fb59dcea54678a693c2533f84b188f
172.17.0.2
[root@k8s-node1 feverasa]#
[root@k8s-node1 feverasa]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
..................
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 192.168.127.129 netmask 255.255.255.0 broadcast 192.168.127.255
.............
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0
.............
veth0e4fa72: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...........
[root@k8s-node1 feverasa]# docker run -d --name springboot2 spring_docker_test:0.0.7
2333a32ecedd9ec07555856fe5fbce75e1d864160fef3f0a8e5f1f54a68fcb42
[root@k8s-node1 feverasa]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2333a32ecedd9ec07555856fe5fbce75e1d864160fef3f0a8e5f1f54a68fcb42
172.17.0.3
[root@k8s-node1 feverasa]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
...........
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 192.168.127.129 netmask 255.255.255.0 broadcast 192.168.127.255
..............
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0
...............
veth020e120: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
.............
veth0e4fa72: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500............
[root@k8s-node1 feverasa]#
在上面的案例中,我们的linux虚拟宿主机的ip是192.168.127.129
,我们的网桥就是docker0,其的ip是172.17.0.1
,我们启动一个容器实例其给这个实例分配的ip是172.17.0.2
,同是有一个新的veth-veth0e4fa72
与这个容器连通。之后我们再起一个容器实例,这个实例的ip是172.17.0.3
,新的veth-veth020e120
。下面我们进入到2333a32ecedd9ec075558
这个容器实例里面
[root@k8s-node1 feverasa]# docker exec -it 2333a32ecedd9ec07555856fe5fbce75e1d864160fef3f0a8e5f1f54a68fcb42 /bin/sh
/wls/appsystems # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.198 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.089 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.089/0.143/0.198 ms
/wls/appsystems #
/wls/appsystems # ping 172.17.0.1
PING 172.17.0.1 (172.17.0.1): 56 data bytes
64 bytes from 172.17.0.1: seq=0 ttl=64 time=0.123 ms
64 bytes from 172.17.0.1: seq=1 ttl=64 time=0.090 ms
^C
--- 172.17.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.090/0.106/0.123 ms
/wls/appsystems # ping 192.168.127.129
PING 192.168.127.129 (192.168.127.129): 56 data bytes
64 bytes from 192.168.127.129: seq=0 ttl=64 time=0.095 ms
64 bytes from 192.168.127.129: seq=1 ttl=64 time=0.148 ms
^C
--- 192.168.127.129 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.095/0.121/0.148 ms
/wls/appsystems # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03 inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:17 errors:0 dropped:0 overruns:0 frame:0TX packets:9 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:1370 (1.3 KiB) TX bytes:714 (714.0 B)lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0
......................
可以看到我们各个网络都是通的。
2、网络路由
[root@k8s-node1 feverasa]# ip route
default via 192.168.127.2 dev ens33 proto dhcp metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1
192.168.127.0/24 dev ens33 proto kernel scope link src 192.168.127.129 metric 100
[root@k8s-node1 feverasa]#
1.1、第一条表示的是默认路由,没有找到对应目的ip的路由,就交给这个路由信息,这个ens33
就是我们的宿主机的etho
,前面我们的ipconfig也可以看到这个ens33
,同时这个192.168.127.2
是我们vmware虚拟机对应的网关信息
1.2、然后第二条172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
,就表示对应的172.17
对应的网段就交给docker0
,docker0
就是我们上面的容器网桥。这个信息文心一言解释一下
2.4、网络防火墙Netfilter和iptables
下面我们的这个内容会与linux的Netfilter和iptables相关,具体的可以搜索下其他的文章了解。
简单来说,就是linux在通过网络进行交互的时候,不管是进入主机的网络数据包、还是出去的,都能进行对应网络处理,进行过滤、修改和转发这些。例如网络进入主机前进行对应规则校验,看这个数据包要不要进入到主机、能不能进入到主机,网络出去的时候修改对应的源IP、或者目的IP啥的。上面提到的Netfilter
就是在linux内核内部进行网络相关的处理,而iptables
是提供的工具,你通过iptables
进行的操作都是交给Netfilter
来进行工作运行的。
对于本机的网络报文数据,一般三条链路:流入本机的报文、从本机流出的报文、流到本机但本机只是起到转发的作用。对于这些,Netfilter
主要提供了5个钩子函数:PREROUTING、INPUT、FORWARD、OUTPUT和POSTROUTING,分别对应数据包进入和离开网络栈的不同阶段。同时还有对应的表来记录对应的规则用来对网络做对应的处理,例如 filter表、nat表、mangle表。
3.1各种规则表介绍
1、filter表是Netfilter默认的表,也是最常用的表。它主要用于实现数据包过滤和网络访问控制,允许或拒绝数据包的传输。例如通过filter表可以定义规则,允许或拒绝特定类型的数据包进入或离开系统,从而增强系统的安全性。
2、nat表用于实现网络地址转换(NAT)。它允许对数据包的源地址和目标地址进行转换,通常用于连接多个私有网络到公共网络(例如,将内部IP地址映射为公共IP地址、将外部对某个公共IP地址和端口的访问转发到内部网络中的特定IP地址和端口上)。
3、mangle表用于修改数据包的头部信息,包括TTL(Time To Live)、TOS(Type Of Service)等字段。它主要用于对数据包进行特殊处理或标记,例如在数据包通过mangle表时,可以修改其TTL值,以控制数据包的生存时间。
4、raw表用于配置数据包绕过连接追踪(connection tracking)机制。当数据包需要完全自主处理时,可以使用raw表。
5、security表通常用于与安全模块SELinux(Security-Enhanced Linux)一起工作,用于基于安全策略的数据包过滤和处理。
3.2、PREROUTING
PREROUTING链是用于处理刚到达本机并在路由转发前的数据包的链,其主要是在数据包被路由到最终目的地之前,能对数据包进行目的地址转换(DNAT)、端口转发等操作。处理这个阶段的主要是mangle和nat表的规则,例如进行端口映射,将一个外部请求的端口映射到另一个端口。
3.3、INPUT
INPUT链是filter表中用于处理进入本地主机的数据包的链,可以对进入的数据包进行过滤和规则匹配,以决定是否允许数据包进入本地系统。例如网络防火墙、或者其他的访问控制。
3.4、FORWARD
FORWARD链是filter表中用于处理经过本机进行转发的数据包的链。这些数据包既不是进入本地系统的,也不是从本地系统发出的,而是经过本机路由到其他网络或主机的。
3.5、OUTPUT
OUTPUT链是filter表中用于处理从本地主机发出的数据包的链。这些数据包一般是主机应用程序生成的,需要发送到网络上的其他主机或服务器。这个的话,我们一般可以网络数据包对外的发出,例如我们在公司的标机就可以对访问外网进行控制,控制访问哪些目的ip能出去,哪些不能发出。
3.6、POSTROUTING
POSTROUTING链是mangle、nat和raw表中用于处理将要离开本机的数据包的链。在数据包离开本地主机后,POSTROUTING链允许对数据包进行源地址转换(SNAT)、修改报头信息等操作。
3.7、容器网络Netfilter链路案例
下面我们来看下使用的案例
[root@k8s-node1 feverasa]# docker run -d -p 8083:8087 spring_docker_test:0.0.7 /bin/bash
2c8d417aa02776bd89f9b236bcb2464e53ddbe247cd97919ace114fa21f82fe2
[root@k8s-node1 feverasa]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2c8d417aa02776bd89f9b236bcb2464e53ddbe247cd97919ace114fa21f82fe2
172.17.0.2
[root@k8s-node1 feverasa]# iptables-save
# Generated by iptables-save v1.4.21 on Sun Sep 22 11:41:54 2024
*mangle
:PREROUTING ACCEPT [10797:3011175]
:INPUT ACCEPT [10797:3011175]
..........
COMMIT
# Completed on Sun Sep 22 11:41:54 2024
# Generated by iptables-save v1.4.21 on Sun Sep 22 11:41:54 2024
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
...........
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
.........
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8087 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8083 -j DNAT --to-destination 172.17.0.2:8087
..............
COMMIT
# Completed on Sun Sep 22 11:41:54 2024
# Generated by iptables-save v1.4.21 on Sun Sep 22 11:41:54 2024
*filter
:INPUT ACCEPT [96:8698]
:FORWARD ACCEPT [0:0]
................
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8087 -j ACCEPT
...................
COMMIT
# Completed on Sun Sep 22 11:41:54 2024
[root@k8s-node1 feverasa]# ip route
default via 192.168.127.2 dev ens33 proto dhcp metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1
192.168.127.0/24 dev ens33 proto kernel scope link src 192.168.127.129 metric 100
[root@k8s-node1 feverasa]#
上面这里我们是启动了一个容器实例,然后进行了端口映射-p 8083:8087
,也就是将请求到宿主机的8083
映射到容器的8087
端口。然后我们看下面的规则:我们可以看到这里主要用来两个表nat
、filter
规则:
*nat
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8083 -j DNAT --to-destination 172.17.0.2:8087
*filter
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8087 -j ACCEPT
对于nat
的规则:也就是将所有不是来自docker0
接口、目标端口为8083的TCP数据包的目标地址和端口更改为172.17.0.2:8087,这样的话,再结合路由172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
规则,就能交给容器网桥来处理,从而请求就能到我们对应的容器实例来处理了。
[root@k8s-node1 feverasa]# iptables -t nat -L DOCKER -n -v
Chain DOCKER (2 references)pkts bytes target prot opt in out source destination 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0 0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8083 to:172.17.0.2:8087
[root@k8s-node1 feverasa]#
对于filter
规则:这条规则的作用是允许从宿主机(或其他网络接口,除了docker0
)发往容器IP地址(172.17.0.2
)和端口(8087
)的TCP数据包,通过docker0
桥接接口进行转发,而不被iptables的默认策略所拒绝
[root@k8s-node1 feverasa]# iptables -t filter -L DOCKER -n -v
Chain DOCKER (1 references)pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:8087
[root@k8s-node1 feverasa]#
三、Kubernetes 的网络实现
Kubernetes集群会设计到Node内部、Pod内部、不同Node之间的问题,其主要是需要解决:
(1)容器到容器之间的直接通信。
(2)Pod到Pod之间的通信。
(3)Pod到Service之间的通信。
(4)集群内部与外部组件之间的通信。
1、同pod容器到容器
同一个Pod内的容器(Pod内的容器是不会跨宿主机的)共享同一个网络命名空间,共享同一个Liux协议栈。所以对于网络的各类操作,就和它们在同一台机器上一样,它们之间借助容器网桥进行通信。
2、同Node上的Pod到Pod的通信
同Node上的Pod的通信,就是借助容器网桥来进行通信。
3、不同Node上的Pod的通信
我们知道一般容器、Pod都是通过网桥模式来与宿主机通信的,容器网络与宿主机网卡的网络一般都是不同的,他们不是同一个网络。所以我们不同Node之间的通信要通过宿主机的物理网卡进行,因此要想实现不同Node上Pod容器之间的通信,就必须想办法通过主机的这个IP地址进行寻址和通信。同时我们也要知道哪个Pod的Ip是在哪台Node主机上,也就是说,先要找到Node对应宿主机的IP地址,将数据发送到这个宿主机的网卡,然后在宿主机上将相应的数据转发到具体的dockero上。当数据到达宿主机Node,那个Node内部的dockero便知道如何将数据发送到Pod了。
下面我们就通过iptable根据来看下其对网络的处理过程:
我们启动部署3个pod、同时配置对应的service,添加对应的NodePort
[root@k8s-master k8s]# cat my_spring_deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: spring-test-deployment
# namespace: demolabels:app: spring-test
spec:replicas: 3strategy:type: RollingUpdaterollingUpdate:maxSurge: 1maxUnavailable: 1selector:matchLabels:app: spring-testtemplate:metadata:labels:app: spring-testspec:containers:- name: spring-test-containerimage: spring_docker_test:0.0.7command: [ "java","-jar","app.jar" ] #启动命令imagePullPolicy: NeverreadinessProbe:tcpSocket:port: 8087initialDelaySeconds: 30periodSeconds: 5failureThreshold: 10timeoutSeconds: 5successThreshold: 1livenessProbe:tcpSocket:port: 8087initialDelaySeconds: 30periodSeconds: 3failureThreshold: 1timeoutSeconds: 3successThreshold: 1ports:- containerPort: 8087
[root@k8s-master k8s]# cat my_spring_service.yaml
apiVersion: v1
kind: Service
metadata:name: spring-test-service# namespace: demo
spec:selector:app: spring-testports:- protocol: TCPport: 8081targetPort: 8087nodePort: 30080 # 如果你想要通过 NodePort 访问,可以添加这一行type: NodePort # 如果你想要通过 NodePort 访问,使用 NodePort;否则使用 ClusterIP
[root@k8s-master k8s]#
我们再通过iptables-save查看nat表对目的地址的处理,这里有一大堆东西,我们主要分析nat表对目的地址的处理。
[root@k8s-node1 feverasa]# iptables-save
# Generated by iptables-save v1.4.21 on Mon Oct 7 17:16:10 2024
*mangle
:PREROUTING ACCEPT [11294:3551519]
.............
-A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT
# Completed on Mon Oct 7 17:16:10 2024
# Generated by iptables-save v1.4.21 on Mon Oct 7 17:16:10 2024
*nat
:PREROUTING ACCEPT [1:67].......................
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
-A POSTROUTING -m comment --comment "flanneld masq" -j FLANNEL-POSTRTG
-A DOCKER -i docker0 -j RETURN
-A FLANNEL-POSTRTG -m mark --mark 0x4000/0x4000 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG -s 10.244.1.0/24 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG -s 10.244.0.0/16 -d 10.244.1.0/24 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.1.0/24 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/spring-test-service:" -m tcp --dport 30080 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/spring-test-service:" -m tcp --dport 30080 -j KUBE-SVC-QVYGXMY2EHJ7RAFE
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
-A KUBE-SEP-3O4DEWC3J3BWX72A -s 10.244.1.116/32 -m comment --comment "default/spring-test-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-3O4DEWC3J3BWX72A -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.116:8087
-A KUBE-SEP-56MKUVBF4GYNJCVZ -s 192.168.127.133/32 -m comment --comment "default/kubernetes:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-56MKUVBF4GYNJCVZ -p tcp -m comment --comment "default/kubernetes:https" -m tcp -j DNAT --to-destination 192.168.127.133:6443
-A KUBE-SEP-BIYY7O5X6UR6HHXF -s 10.244.1.113/32 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-MARK-MASQ
-A KUBE-SEP-BIYY7O5X6UR6HHXF -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m tcp -j DNAT --to-destination 10.244.1.113:53
-A KUBE-SEP-G3MN2O4GTAP3PDK2 -s 10.244.1.117/32 -m comment --comment "default/spring-test-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-G3MN2O4GTAP3PDK2 -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.117:8087
-A KUBE-SEP-LKOJGVHBLSDGTBKL -s 10.244.1.115/32 -m comment --comment "default/spring-test-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-LKOJGVHBLSDGTBKL -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.115:8087
-A KUBE-SEP-NJEYY2XOHHMI4352 -s 10.244.1.114/32 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-MARK-MASQ
-A KUBE-SEP-NJEYY2XOHHMI4352 -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.244.1.114:53
-A KUBE-SEP-NLMKBI6PSBPGIFSO -s 10.244.1.114/32 -m comment --comment "kube-system/kube-dns:metrics" -j KUBE-MARK-MASQ
-A KUBE-SEP-NLMKBI6PSBPGIFSO -p tcp -m comment --comment "kube-system/kube-dns:metrics" -m tcp -j DNAT --to-destination 10.244.1.114:9153
-A KUBE-SEP-PRCWKCQTPENAJ4KN -s 10.244.1.113/32 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-MARK-MASQ
-A KUBE-SEP-PRCWKCQTPENAJ4KN -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.244.1.113:53
-A KUBE-SEP-RCY2T2CQ6GPUVOKB -s 10.244.1.114/32 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-MARK-MASQ
-A KUBE-SEP-RCY2T2CQ6GPUVOKB -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m tcp -j DNAT --to-destination 10.244.1.114:53
-A KUBE-SEP-TKZGQ5DGIXMLDELT -s 10.244.1.113/32 -m comment --comment "kube-system/kube-dns:metrics" -j KUBE-MARK-MASQ
-A KUBE-SEP-TKZGQ5DGIXMLDELT -p tcp -m comment --comment "kube-system/kube-dns:metrics" -m tcp -j DNAT --to-destination 10.244.1.113:9153
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.107.178.62/32 -p tcp -m comment --comment "default/spring-test-service: cluster IP" -m tcp --dport 8081 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.107.178.62/32 -p tcp -m comment --comment "default/spring-test-service: cluster IP" -m tcp --dport 8081 -j KUBE-SVC-QVYGXMY2EHJ7RAFE
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-SVC-JD5MR3NA4I4DYORP
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-ERIFXISQEP7F7OF4 -m comment --comment "kube-system/kube-dns:dns-tcp" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-BIYY7O5X6UR6HHXF
-A KUBE-SVC-ERIFXISQEP7F7OF4 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-SEP-RCY2T2CQ6GPUVOKB
-A KUBE-SVC-JD5MR3NA4I4DYORP -m comment --comment "kube-system/kube-dns:metrics" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-TKZGQ5DGIXMLDELT
-A KUBE-SVC-JD5MR3NA4I4DYORP -m comment --comment "kube-system/kube-dns:metrics" -j KUBE-SEP-NLMKBI6PSBPGIFSO
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https" -j KUBE-SEP-56MKUVBF4GYNJCVZ
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-LKOJGVHBLSDGTBKL
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3O4DEWC3J3BWX72A
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -j KUBE-SEP-G3MN2O4GTAP3PDK2
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-PRCWKCQTPENAJ4KN
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns" -j KUBE-SEP-NJEYY2XOHHMI4352
COMMIT
# Completed on Mon Oct 7 17:16:10 2024
# Generated by iptables-save v1.4.21 on Mon Oct 7 17:16:10 2024
*filter...........
COMMIT
# Completed on Mon Oct 7 17:16:10 2024
[root@k8s-node1 feverasa]#
[root@k8s-node1 feverasa]#
[root@k8s-node1 feverasa]# ps -ef | grep kube-proxy
root 6786 6766 0 17:01 ? 00:00:00 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=k8s-node1
root 14447 3576 0 17:17 pts/0 00:00:00 grep --color=auto kube-proxy
首先通过我们定义的Service
,其的NodePort是30080
,然后其的ClusterPort是8081,3个pod对应的端口是8087是。
[root@k8s-master k8s]# kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default spring-test-deployment-5d5c8869bf-5ssvm 1/1 Running 0 76m 10.244.1.116 k8s-node1 <none> <none>
default spring-test-deployment-5d5c8869bf-jtblz 1/1 Running 0 76m 10.244.1.117 k8s-node1 <none> <none>
default spring-test-deployment-5d5c8869bf-t6tnp 1/1 Running 0 76m 10.244.1.115 k8s-node1 <none> <none>
............
在这里面我们提前这些信息
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/spring-test-service:" -m tcp --dport 30080 -j KUBE-SVC-QVYGXMY2EHJ7RAFE
-A KUBE-SERVICES -d 10.107.178.62/32 -p tcp -m comment --comment "default/spring-test-service: cluster IP" -m tcp --dport 8081 -j KUBE-SVC-QVYGXMY2EHJ7RAFE
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-LKOJGVHBLSDGTBKL
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3O4DEWC3J3BWX72A
-A KUBE-SVC-QVYGXMY2EHJ7RAFE -m comment --comment "default/spring-test-service:" -j KUBE-SEP-G3MN2O4GTAP3PDK2
-A KUBE-SEP-LKOJGVHBLSDGTBKL -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.115:8087
-A KUBE-SEP-3O4DEWC3J3BWX72A -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.116:8087
-A KUBE-SEP-G3MN2O4GTAP3PDK2 -p tcp -m comment --comment "default/spring-test-service:" -m tcp -j DNAT --to-destination 10.244.1.117:8087
这里当我们对30080
、8081
对口请求的分发就是通过KUBE-SVC-QVYGXMY2EHJ7RAFE
来进行分发处理,其有三条分发策略,定义不同的概率0.33333333349
对应的是LKOJGVHBLSDGTBKL
也就是10.244.1.115:8087
这个pod进行处理、0.50000000000
对应的是3O4DEWC3J3BWX72A
处理的是10.244.1.116:8087
这个pod、剩下的就是G3MN2O4GTAP3PDK2
这个默认的处理pod10.244.1.117:8087
,然后我们可以看到这里对应的追加的3条nat数据KUBE-SEP-LKOJGVHBLSDGTBKL
、KUBE-SEP-3O4DEWC3J3BWX72A
、KUBE-SEP-G3MN2O4GTAP3PDK2
,这3条就是修改请求,将其的目的地址修改为对应的pod引用的请求地址+端口。
而对于3个pod地址路由的处理:
[root@k8s-node1 feverasa]# ifconfig
cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450inet 10.244.1.1 netmask 255.255.255.0 broadcast 10.244.1.255inet6 fe80::b03c:7aff:fed2:76d8 prefixlen 64 scopeid 0x20<link>ether b2:3c:7a:d2:76:d8 txqueuelen 1000 (Ethernet)RX packets 384 bytes 27505 (26.8 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 438 bytes 146544 (143.1 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
............
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 192.168.127.129 netmask 255.255.255.0 broadcast 192.168.127.255inet6 fe80::7637:f8c5:6495:e97 prefixlen 64 scopeid 0x20<link>ether 00:0c:29:57:69:f9 txqueuelen 1000 (Ethernet)RX packets 2221 bytes 1332152 (1.2 MiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 1926 bytes 243378 (237.6 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450inet 10.244.1.0 netmask 255.255.255.255 broadcast 0.0.0.0inet6 fe80::e87a:45ff:fe75:653c prefixlen 64 scopeid 0x20<link>ether ea:7a:45:75:65:3c txqueuelen 0 (Ethernet)RX packets 0 bytes 0 (0.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 27 overruns 0 carrier 0 collisions 0
...............
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255ether 52:54:00:5d:fa:5d txqueuelen 1000 (Ethernet)RX packets 0 bytes 0 (0.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0[root@k8s-node1 feverasa]# ip route
default via 192.168.127.2 dev ens33 proto dhcp metric 100
10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink
10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.127.0/24 dev ens33 proto kernel scope link src 192.168.127.129 metric 100
[root@k8s-node1 feverasa]#
这上面cni0
这个就是对应k8s定义的容器网络接口规范CNI产生的一个虚拟网桥,用于连接同一节点上的容器或Pod。而对应CNI的具体实现,我目前安装的插件是flannel,flannel.1
是插件flannel产生的。然后对于路由10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink
,则是网络发送的接口是flannel.1
。具体内部对应不同Node的网络通信实现就是CNI与具体的网络实现相关,例如flannel,这里我们就不深究了,应该也是对于pod的ip也NodeIP的一些映射关系,或者其他其他的什么方案。当我们通过上面的这些nat
规则,也能大概了解其的处理过程。
相关文章:

K8S系列-Kubernetes网络
一、Kubernetes网络模型 Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中,不管它们是否运行在同一个Node(宿主机)中,都…...

Excel 对数据进行脱敏
身份证号脱敏:LEFT(A2,6)&REPT("*",6)&RIGHT(A2,6) 手机号脱敏:LEFT(B2,3)&REPT("*",5)&RIGHT(B2,3) 姓名脱敏:LEFT(C2,1)&REPT("*",1)&RIGHT(C2,1) 参考: excel匹配替换…...

OJ-1014田忌赛马
示例1: 输入 11 8 20 10 13 7 输出 1 示例2: 输入 11 12 20 10 13 7 输出 2 示例3: 输入 1 2 3 4 5 6 输出 6 解题思路: 问题的关键在于调整数组a的顺序,使得尽可能多的a[i] > b[i]。为了达到最优结果,我们可以采用贪心的策…...

Excel重新踩坑3:条件格式;基本公式运算符;公式中的单元格引用方式;公式菜单栏其他有用的功能说明;
0、前言:以下内容是学习excel公式的基础内容。 1、需求:将表格特定区域中数值大小大于等于30,小于等于80的单元格,颜色填充为红色,大于80的,颜色填充为黄色。 新建规则之后也可以通过该功能清除规则。 2、基…...

【AI知识点】FAISS如何提高检索效率?
【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】 FAISS(Facebook AI Similarity Search) 是一个高效的相似度搜索库,专门设计用于处理大规模的向量检索任务,尤其是在稠密向量的检索中表现出色。FAISS 能够显著提高检索效率…...

【Git】Gitlab进行merge request的时候,出现待合并分支合并了主分支的问题的解决
最近在公司开始用merge request进行代码合并了。 然后不知道为啥,如果待合并分支(A)进行merge request到主分支(B)的时候,如果A和B有冲突,然后我在gitlab上使用页面进行冲突的解决,比…...

jetson nano ubuntu20.04安装ros-Noetic
jetson nano ubuntu20.04 安装ros-Noetic 一. 初始准备nano连接wifinano网络配置二. 查看系统版本三. 开始安装1. 移除不需要的 amd64 架构2. 配置软件源3.安装 ROS Melodic`4. 解决 rosdep update报错`一. 初始准备 nano连接wifi nano网络配置 二. 查看系统版本 lsb_relea…...

【数据结构与算法】走进数据结构的“时间胶囊”——栈
大家好,我是小卡皮巴拉 文章目录 目录 引言 一.栈的基本概念 1.1 定义 1.2 特性 1.3 基本操作 二.栈的实现方式 2.1 顺序栈 2.2 链栈 三.顺序栈的实现 定义顺序栈的结构 初始化 入栈 检查栈是否为空 出栈 销毁 四.链栈的实现 定义链栈的结构 初始…...

伺服增量式和绝对式的本质区别?
伺服增量式和绝对式的本质区别? 增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。以转动时输出脉冲,通过计数设备来知道其位置,当编码器不动或停电时,…...

应对 .DevicData-X-XXXXXXXX 勒索病毒:防御与恢复策略
引言 随着信息技术的快速发展,网络安全问题愈发严峻。勒索病毒作为一种恶性网络攻击手段,已成为企业和个人面临的重大威胁之一。尤其是 .DevicData-X-XXXXXXXX 勒索病毒,其通过加密用户数据并勒索赎金,给受害者带来了巨大的经济损…...

【代码随想录——数组——二刷】
数组 1. 二分查找(704) 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 1.1 二分法的第一种写法 我们定义 target 是在…...

spring-boot(4)
1.VueRouter安装与使用 2.状态管理VueX 3. 4. 5. 6....

深度学习模型:原理、架构与应用
深度学习(Deep Learning)是机器学习中的一个分支,基于人工神经网络的发展,尤其是多层神经网络的研究,使其在语音识别、图像处理、自然语言处理等领域取得了显著进展。深度学习的核心是通过大量数据的训练,学习到数据的内在结构和模式,并且具备自动从复杂的输入中提取特征…...

玩客云Armbian安装Casaos
#armbian安装docker apt install docker.io #armbian判断docker是否正常运行 systemctl status docker #查看版本 docker version #安装casaos方式一 wget -qO- https://get.casaos.io | bash #安装casaos方式二 curl -fsSL https://get.casaos.io | bash...

redis过期提醒
文章目录 redis过期提醒 redis过期提醒 有一次看redis的配置文件发现一个notify-keyspace-events配置,注释里边长篇大论的,那我得看看这是干啥的,看完注释内容,发现不得了了,redis竟然还有过期提醒的功能 接下来得大…...

AnaTraf | 提升网络性能:深入解析网络关键指标监控、TCP重传与TCP握手时间
AnaTraf 网络性能监控系统NPM | 全流量回溯分析 | 网络故障排除工具 在当今的数字化时代,网络的稳定性和性能对企业的运营效率至关重要。无论是内部通信、应用程序的运行,还是对外提供服务,网络都发挥着关键作用。对于网络工程师或IT运维人员…...

黑盒测试和白盒测试的具体方法(附加实际应用中的技巧和注意事项)
黑盒测试的具体方法 黑盒测试有多种具体的方法,以下是几种常见的黑盒测试技术: 等价类划分 定义:将输入数据划分为若干等价类,每个等价类中的数据被认为是等效的。目的:减少测试用例数量,同时覆盖所有可…...

基于ssm的小区物业管理系统
文未可获取一份本项目的java源码和数据库参考。 题目简介: 我国物权法的颁布以及经济的快速发展进一步提升了社区居民对物业服务和物业管理的要求,特别是对于社区安全、社区停车以及社区维修等各个方面提出了更为严格的要求。在这种背景下社区物业必须…...

4本SCI/SSCI期刊更名,10月WOS更新!速看!
期刊动态 2024年10月科睿唯安期刊目录更新 2024年10月22日,科睿唯安更新了WOS期刊目录,此次更新,期刊被编辑除名11本,停止出版1本,4本更名,停产1本,新增63本。 剔除期刊 11本期刊被剔 Enginee…...

麒麟v10系统安装docker镜像
最近把系统搞崩了,又重新安装了一个麒麟系统,yum更新发现不能安装docker,所以这里给出一个安装教程,分享出来,让大家少走弯路: # 配置阿里云 Centos8 镜像源,需要额外的一些依赖,而…...

基于SSM大学校医院信息管理系统的设计
管理员账户功能包括:系统首页,个人中心,校医管理,用户管理,在线问诊管理,线上挂号管理,病例记录管理,系统管理 校医账号功能包括:系统首页,个人中心…...

【JS】如何识别一个变量是不是数组对象
文章目录 1. Array.isArray()语法示例 2. Object.prototype.toString.call()语法示例 3. instanceof 操作符语法示例 4. 检查 constructor属性语法示例 总结 在 JavaScript 中,有几种方法可以用来识别一个变量是否是数组对象。以下是一些常用的方法: 1. …...

探索 Python 幽默之源:pyjokes 库全解析
🚀 探索 Python 幽默之源:pyjokes 库全解析 1. 背景介绍:为何选择 pyjokes? 在紧张的编程工作中,幽默是一种有效的缓解压力的方式。pyjokes 是一个专为程序员设计的 Python 库,它提供了丰富的单行笑话&am…...

苦寻多时,终于找到!这款免费GIS工具助你轻松搞定地形切片
概述 地形切片是将大范围的地形数据分割成小块(切片)进行存储和展示的技术,常用于高效的三维地形可视化和动态加载。在实际操作中,可以通过GISBox等工具进行地形切片处理。今天和大家安利的GISBox 是一个用于GIS模型切片、服务分…...

OpenResty性能分析:以HelloWorld服务器为例
软考鸭微信小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 在Web开发领域,性能是衡量服务器和应用质量的重要指标之一。对于简单的HelloWorld服务器,虽然其功能有限,但通过对其性能…...

pb生成文件和反射
1.protoc生成文件 指定生成的目录和proto文件路径, protoc --cpp_out./ ./echo.proto // echo.proto syntax "proto3";package echo;option cc_generic_services true;message EchoRequest {string msg 1; }message EchoResponse {string msg 2; }…...

.net framework 3.5sp1安装错误卡住不动怎么解决
解决 .NET Framework 3.5 SP1 安装错误卡住的问题,可以尝试以下几种方法: 1.使用 DISM 工具: 将下载的 NetFx3.cab 文件放置在 C:\Windows 文件夹下。 以管理员身份打开命令提示符,输入以下命令: dism /online /En…...

毕业设计—基于 Inception-ResNet模型的皮肤癌分类系统实现
1.摘要 皮肤癌是人类最常见的恶性肿瘤,主要通过视觉诊断进行初步临床筛查。但是由于皮肤病变外观的细微变化性,使用图像自动分类皮肤病变是一项具有挑战性的任务。本文为了提高深度学习算法在皮肤病检测上的准确率,本文提出了基于Inception和…...

什么是优秀的单元测试?
阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大! 单元测试的质量意义 合理编写单元测试,可使团队工程师告别牛仔式编程,产出易维护的高质量代码。随着单元测试覆盖率的上升,项目会更加…...

服务器安装Anaconda,Anaconda安装Pytorch
1.服务器安装Anaconda 1.1 下载Anaconda 在服务器上直接下载 wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh1.2 安装Anaconda bash Anaconda3-2024.06-1-Linux-x86_64.sh然后就显示下面:more 安装过程一直enter即可,…...