【kubernetes】二进制部署k8s集群之cni网络插件flannel和calico工作原理(中)

↑↑↑↑接上一篇继续部署↑↑↑↑

目录

一、k8s集群的三种接口

二、k8s的三种网络模式

1、pod内容器之间的通信

2、同一个node节点中pod之间通信

3、不同的node节点的pod之间通信

Overlay Network

VXLAN

三、flannel网络插件

1、flannel插件模式之UDP模式(8285端口)

2、flannel插件模式之VXLAN模式

3、总结flannel插件的三大模式

4、拓展:关于vlan和vxlan的区别

四、calico网络插件

1、calico插件模式之IPIP模式

2、calico插件模式之BGP模式

3、总结calico插件三大模式

五、对比flannel和calico的区别

六、在所有node节点部署cni网络插件之flannel的vxlan模式

七、在所有node节点上部署coreDNS

八、最后拓展calico插件部署


一、k8s集群的三种接口

前言,k8s集群有三大接口:

CRI:容器进行时接口,连接容器引擎--docker、containerd、cri-o、podman

CNI:容器网络接口,用于连接网络插件如:flannel、calico、cilium

CSI:容器存储接口,如nfs、ceph、gfs、oss、s3、minio

二、k8s的三种网络模式

k8s集群中pod网络通信分类

1、pod内容器之间的通信

在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享同一个网络命令空间,相当于它们在同一台机器上一样,可以用 localhost 地址访问彼此的端口

2、同一个node节点中pod之间通信

每个 Pod 都有一个真实的全局 IP 地址,同一个 Node 内的不同 Pod 之间可以直接采用对方 Pod 的 IP 地址进行通信Pod1 与 Pod2 都是通过 Veth 连接到同一个 docker0 网桥,网段相同,所以它们之间可以直接通信

3、不同的node节点的pod之间通信

Pod 地址与 docker0 在同一网段,docker0 网段与宿主机网卡是两个不同的网段,且不同 Node 之间的通信只能通过宿主机的物理网卡进行
要想实现不同 Node 上 Pod 之间的通信,就必须想办法通过主机的物理网卡 IP 地址进行寻址和通信。因此要满足两个条件:①Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,②通过这个关联让不同 Node 上 Pod 之间直接通过内网 IP 地址通信。

总结:因此引入了cni网络插件的核心原因实际上就是为了解决不同node节点上的不同pod之间的通信,即pod跨主机通信

关于k8s的三种类型的网络IP

节点网络:nodeIP---node节点的物理网卡ip,实现node节点之间的通信

Pod网络:PodIP---Pod与Pod之间通过PodIP进行通信

service网络:clusterIP---k8s集群内部,service资源的clusterIP实现对Pod集群的网络代理

Overlay Network

叠加网络,在二层或者三层基础网络上叠加的一种虚拟网络技术模式,该网络中的主机通过虚拟链路隧道连接起来(类似于VPN)

个人理解为正常的数据包是一层 也就是【mac头+ip头+udp/tcp头+真实数据】,这种叠加网络就是说把【mac头+ip头+udp/tcp头+真实数据】看做一个整体,作为真实数据 再次封装,{【mac头+ip头+udp/tcp头】+【mac头+ip头+udp/tcp头+真实数据】} 这种看成一个整体

VXLAN

将源数据包封装到UDP中,并使用基础网络的IP/MAC作为外层报文头进行封装,然后在以太网上传输,到达目的地后由隧道端点解封装并将数据发送给目标地址。

三、flannel网络插件

Flannel 的功能是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址
Flannel 是 Overlay 网络的一种,也是将 TCP 源数据包封装在另一种网络包里面进行路由转发和通信目前支持 udp、vxlan、 host-GW 3种数据转发方式

1、flannel插件模式之UDP模式(8285端口)

第一步:原始的数据包从pod容器发送给cni0网桥,cni0网桥将数据包发送给flannel0虚拟接口

第二步:flanneld服务进程会监听flannel.0接口接收的数据,flanneld服务进程将数据包封装到UDP的报文中(叠加封装)

第三步:flanneld服务进程会通过etcd数据库查询路由表信息,找到关于目标pod所在的node节点的ip,然后在UDP报文外再次封装nodeip头部、mac头部,并通过物理网卡发送给目标node节点

第四步:UDP报文通过8285端口送达到目标node节点的flanneld进程进行解封装,在根据本地的路由表规则通过flannel0接口发送到cni0网桥,再由cni0发送给目标pod容器

总结:udp模式的工作核心是基于flanneld应用进行原始数据包封装在udp报文中,属于overlay网络的一种

#ETCD 之 Flannel 提供说明:
①功能1:存储管理Flannel可分配的IP地址段资源
②功能2:监控 ETCD 中每个 Pod 的实际地址,并在内存中建立维护 Pod 节点路由表

由于 udp 模式是在用户态做转发,会多一次报文隧道封装,因此性能上会比在内核态做转发的 vxlan 模式差。

2、flannel插件模式之VXLAN模式

第一步:原始数据帧从源主机的pod容器发出到cni0网桥,再由cni0转发给flannel.1虚拟接口

第二步:flannel.1接口接收数据帧以后先添加vxlan头部,然后在内核将原始数据帧封装在UDP报文中

第三步:flanneld会查询etcd中的路由表信息获取目标pod的nodeip,然后再udp报文外封装nodeip头部和mac头部,通过物理网卡发送给目标node节点

第四步:报文会通过8472端口到目标node节点的flannel.1接口,并在内核中解封装,最后根据本地的路由规则转发到cni0网桥,再发送到目标pod容器

3、总结flannel插件的三大模式

UDP——出现最早,性能最差。基于flanneld应用程序实现原始数据包的封装和解封装

VXLAN——是flannel的默认模式,也是推荐使用模式。(与udp模式比:)性能比udp好,基于内核实现原始数据帧的封装和解封装;(与HOST-GW模式比:)配置简单使用方便。

HOST-GW——性能最好的模式,但是配置复杂,且不能跨网段(通过静态路由实现)

4、拓展:关于vlan和vxlan的区别

(1)作用不同:

vlan是用于在交换机上实现逻辑划分广播域,还可以配合stp生成树协议阻塞路径接口,避免产生环路和广播风暴

vxlan是将数据帧封装在udp报文中,通过网络层传输给其他网络,实现虚拟大二层网络通信

(2)数量不同:

vxlan支持更多的二层网络,最多支持2^24个

vlan最多支持2^12个

(3)mac表中的记录不同

vxlan采用的是隧道机制,mac物理地址不需要记录在交换机中

vlan需要在mac表中记录mac地址

四、calico网络插件

●flannel方案
需要在每个节点上把发向容器的数据包进行封装后,再用隧道将封装后的数据包发送到运行着目标Pod的node节点上。目标node节点再负责去掉封装,将去除封装的数据包发送到目标Pod上。数据通信性能则大受影响。

●calico方案
Calico不使用隧道或NAT来实现转发,而是把Host当作Internet中的路由器,使用BGP同步路由,并使用iptables来做安全访问策略,完成跨Host转发来。

#Calico 主要由三个部分组成:
Calico CNI插件:主要负责与kubernetes对接,供kubelet调用使用。
Felix:负责维护宿主机上的路由规则、FIB转发信息库等。
BIRD:负责分发路由规则,类似路由器。

Confd:配置管理组件。

1、calico插件模式之IPIP模式

第一步:原始数据包从源主机的pod发出,通过veth pair设备送达到tunl0接口,再被内核的ipip驱动封装在node节点网络的ip报文中

第二步:根据felix维护的路由规则通过物理网卡发送到目标的node节点

第三步:数据包到达目标node节点的tunl0接口后再通过内核的ipip驱动解封装得到原始数据包,再根据本地的路由规则通过veth pair设备送达到目标pod容器

2、calico插件模式之BGP模式

calico的BGP模式工作原理(本质就是通过路由规则来实现Pod之间的通信)
每个Pod容器都有一个 veth pair 设备,一端接入容器,另一个接入宿主机网络空间,并设置一条路由规则。
这些路由规则都是 Felix 维护配置的,由 BIRD 组件基于 BGP 动态路由协议分发路由信息给其它节点。
1)原始数据包从源主机的Pod容器发出,通过 veth pair 设备送达到宿主机网络空间
2)根据Felix维护的路由规则通过物理网卡发送到目标node节点
3)目标node节点接收到数据包后,会根据本地路由规则通过 veth pair 设备送达到目标Pod容器

3、总结calico插件三大模式

五、对比flannel和calico的区别

(1)从模式来讲

  • flannel插件的模式有:udp、vxlan、host-gw
  • calico插件的模式有:IPIP、BGP、CrossSubnet(混合模式)

(2)从默认网段来讲

  • flannel默认的网段是10.244.0.0/16
  • calico默认的网段是192.168.0.0/16

(3)从模式的性能来讲

flannel

  • 通常会采用VXLAN模式,用的是叠加网络、IP隧道方式传输数据,对性能有一定的影响。
  • Flannel产品成熟,依赖性较少,易于安装,功能简单,配置方便,利于管理。但是不具备复杂的网络策略配置能力。

calico

  • 使用IPIP模式可以实现跨子网传输,但是传输过程中需要额外的封包和解包过程,对性能有一定的影响。
  • 使用BGP模式会把每个node节点看作成路由器,通过Felix、BIRD组件来维护和分发路由规则,可实现直接通过BGP路由协议实现路由转发,传输过程中不需要额外封包和解包过程,因此性能较好,但是只能在同一个网段里使用,无法跨子网传输。
  • calico不使用cni0网桥,而使通过路由规则把数据包直接发送到目标主机,所以性能较高;而且还具有更丰富的网络策略配置管理能力,功能更全面,但是维护起来较为复杂。

(4)从使用场景来讲

  • 对于较小规模且网络要求简单的K8S集群,可以采用flannel作为cni网络插件;
  • 对于K8S集群规模较大且要求更多的网络策略配置时,可以考虑采用性能更好功能更全面的calico或cilium。

六、在所有node节点部署cni网络插件之flannel的vxlan模式

上传flannel-v0.21.5.zip

[root@node01 k8s#unzip flannel-v0.21.5.zip
##上传 flannel-v0.21.5.zip 到 /opt/k8s 目录中,并完成解压

[root@node01 k8s#ls
cni-plugins-linux-amd64-v1.3.0.tgz  flannel-cni-plugin.tar  flannel.tar  flannel-v0.21.5.zip  kube-flannel.yml  kubelet.sh  node.zip  proxy.sh

##导入镜像
[root@node01 k8s#docker load -i flannel-cni-plugin.tar 
[root@node01 k8s#docker load -i flannel.tar 

##查看镜像是否导入成功
[root@node01 k8s#docker images
REPOSITORY                   TAG       IMAGE ID       CREATED         SIZE
flannel/flannel              v0.21.5   a6c0cb5dbd21   9 months ago    68.9MB
flannel/flannel-cni-plugin   v1.1.2    7a2dcab94698   14 months ago   7.97MB

##创建cni网络插件的工作目录
[root@node01 k8s#mkdir -p /opt/cni/bin

#将flannel-v0.21.5.zip解压后的cni-plugins-linux-amd64-v1.3.0.tgz解压到cni网络插件的工作目录
[root@node01 k8s#tar xf cni-plugins-linux-amd64-v1.3.0.tgz -C /opt/cni/bin/
[root@node01 k8s#ls !$
ls /opt/cni/bin/
bandwidth  bridge  dhcp  dummy  firewall  host-device  host-local  ipvlan  loopback  macvlan  portmap  ptp  sbr  static  tap  tuning  vlan  vrf

##将2个镜像和cni工作目录传输给node02节点
[root@node01 k8s#scp flannel-cni-plugin.tar flannel.tar node02:/opt/k8s/    
[root@node01 k8s#scp -r /opt/cni/ node02:/opt/

[root@node01 k8s#scp kube-flannel.yml master01:/opt/k8s/

//在 master01 节点上操作
#上传 kube-flannel.yml 文件到 /opt/k8s 目录中,部署 CNI 网络
cd /opt/k8s
kubectl apply -f kube-flannel.yml 

kubectl get pods -n  kube-flannel
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-hjtc7   1/1     Running   0          7s

kubectl get nodes
NAME            STATUS   ROLES    AGE   VERSION
192.168.20.16   Ready    <none>   81m   v1.20.11

ip -d addr show flannel.1

 要知道网络插件的目的是为了解决跨node节点的pod进行通信,那么验证一下

1.在master01节点创建pod资源

##创建pod
[root@master01 k8s#kubectl create deployment test-v1 --image=soscscs/myapp:v1  --replicas=2

#查看pod状态
[root@master01 k8s#kubectl get pods -o wide

2.在node节点查看容器情况

3.进入容器中 查看是否可以完成跨主机pod通信 

注意:有几个文件中的网段设置需要一致

kube-flannel.yml中的网段设置

与controller manager以及kube-proxy脚本中设置的网段需要保持一致

kube-flannel.yml 

 controller manager脚本

 kube-proxy脚本

七、在所有node节点上部署coreDNS

CoreDNS 是 K8S 默认的集群内部 DNS 功能实现,为 K8S 集群内的 Pod 提供 DNS 解析服务

  • 根据 service 的资源名称 解析出对应的 clusterIP
  • 根据 statefulset 控制器创建的Pod资源名称 解析出对应的 podIP

在所有node节点上上传coredns.tar软件包

//在所有 node 节点上操作
#上传 coredns.tar 到 /opt 目录中
cd /opt
docker load -i coredns.tar

 在master01节点上部署coredns

//在 master01 节点上操作
#上传 coredns.yaml 文件到 /opt/k8s 目录中,部署 CoreDNS 
cd /opt/k8s
kubectl apply -f coredns.yaml

kubectl get pods -n kube-system 

验证可以通过service的名称进行通信

[root@master01 k8s#kubectl get pods --show-labels
##查看当前的pod资源 并展示其label标签
NAME                       READY   STATUS    RESTARTS   AGE   LABELS
test-v1-56f56b4db5-ksplj   1/1     Running   0          25m   app=test-v1,pod-template-hash=56f56b4db5
test-v1-56f56b4db5-z8p2p   1/1     Running   0          25m   app=test-v1,pod-template-hash=56f56b4db5

##查看当前的service资源有哪些
[root@master01 k8s#kubectl get service

[root@master01 k8s#kubectl expose deployment test-v1  --port=80 --target-port=80
##创建service资源
service/test-v1 exposed

 在node节点中进入容器,验证可以通过service资源名称通信 以及可以实现nslookup

 验证service资源可以实现pod集群的四层网络代理,实现负载均衡

八、最后拓展calico插件部署

//在 master01 节点上操作
#上传 calico.yaml 文件到 /opt/k8s 目录中,部署 CNI 网络
cd /opt/k8s
vim calico.yaml
#修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kube-controller-manager配置文件指定的cluster-cidr网段一样
    - name: CALICO_IPV4POOL_CIDR
      value: "192.168.0.0/16"
  
kubectl apply -f calico.yaml

kubectl get pods -n kube-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-659bd7879c-4h8vk   1/1     Running   0          58s
calico-node-nsm6b                          1/1     Running   0          58s
calico-node-tdt8v                          1/1     Running   0          58s

#等 Calico Pod 都 Running,节点也会准备就绪
kubectl get nodes


---------- node02 节点部署 ----------
//在 node01 节点上操作
cd /opt/
scp kubelet.sh proxy.sh root@192.168.20.17:/opt/
scp -r /opt/cni root@192.168.20.17:/opt/

//在 node02 节点上操作
#启动kubelet服务
cd /opt/
chmod +x kubelet.sh
./kubelet.sh 192.168.20.17

//在 master01 节点上操作
kubectl get csr
NAME                                                   AGE  SIGNERNAME                                    REQUESTOR           CONDITION
node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0   10s  kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Pending
node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFE   85m  kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Approved,Issued

#通过 CSR 请求
kubectl certificate approve node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0

kubectl get csr
NAME                                                   AGE  SIGNERNAME                                    REQUESTOR           CONDITION
node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0   23s  kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Approved,Issued
node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFE   85m  kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Approved,Issued

#加载 ipvs 模块
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done

#使用proxy.sh脚本启动proxy服务
cd /opt/
chmod +x proxy.sh
./proxy.sh 192.168.20.17

#查看群集中的节点状态
kubectl get nodes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/403292.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在 Windows 上使用 VC++ 编译 OpenSSL 源码的步骤

在 Windows 上使用 VC 编译 OpenSSL 源码的步骤如下&#xff1a; 准备工作 安装 Visual Studio 2017 或更高版本。安装 Perl 脚本解释器。安装 NASM 汇编器。 编译步骤 下载 OpenSSL 源码。解压 OpenSSL 源码。打开命令行工具&#xff0c;并进入 OpenSSL 源码目录。运行以下…

核密度分析

一.算法介绍 核密度估计&#xff08;Kernel Density Estimation&#xff09;是一种用于估计数据分布的非参数统计方法。它可以用于多种目的和应用&#xff0c;包括&#xff1a; 数据可视化&#xff1a;核密度估计可以用来绘制平滑的密度曲线或热力图&#xff0c;从而直观地表…

[HTML]Web前端开发技术27(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

C++力扣题目 647--回文子串 516--最长回文子序列

647. 回文子串 力扣题目链接(opens new window) 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#xff0c;也会被视作不同的子串。 示例 1&#xff1a; 输入&#xff1a…

Velocity

引入 <dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version> </dependency> 加载 Test public void velo01() throws IOException {// 设置velocity资…

Flutter插件开发指南01: 通道Channel的编写与实现

Flutter插件开发指南01: 通道Channel的编写与实现 视频 https://www.bilibili.com/video/BV1ih4y1E7E3/ 前言 本文将会通过一个加法计算&#xff0c;来实现 Channel 的双向通讯&#xff0c;让大家有个一个体会。 Flutter插件 Flutter插件是Flutter应用程序与原生平台之间的桥…

测试环境搭建整套大数据系统(六:搭建sqoop)

一&#xff1a;下载安装包 https://archive.apache.org/dist/sqoop/ 二&#xff1a;解压修改配置。 tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /opt cd /opt mv sqoop-1.4.7.bin__hadoop-2.6.0/ sqoop-1.4.7修改环境变量 vi /etc/profile#SQOOP_HOME export SQOOP_…

远程连接 vscode 出错 “远程主机可能不符合 glibc 和 libstdc++ VS Code 服务器的先决条件”

原因&#xff1a; vscode 版本是 1.86&#xff0c;服务器上的 glibc 和 libstdc 版本不满足 要求(2.28 和 3.4.25)。 解决&#xff1a; 1、下载 1.85.2&#xff0c;解压直接运行 Code.exe。 2、回退 Remote-ssh 到 0.107.1。 参考&#xff1a; vscode 1.86版本远程ssh不兼容旧…

关于运行flutter app 运行到模拟器出现异常提示

Exception: Gradle task assembleDebug failed with exit code 1 解决方案&#xff1a; 1.讲当前文件的distributionUrl值改为 https://mirrors.cloud.tencent.com/gradle/gradle-7.4-all.zip

【论文解读】Uncertainty Quantification of Collaborative Detection for Self-Driving

Uncertainty Quantification of Collaborative Detection for Self-Driving 摘要引言方法问题定义方法概览Double-M 实验结论 摘要 在联网和自动驾驶汽车(CAVs)之间共享信息从根本上提高了自动驾驶协同目标检测的性能。然而&#xff0c;由于实际挑战&#xff0c;CAV 在目标检测…

$attrs

一、概念 vue官网定义如下: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"传入内部组件——在创建…

C语言翻译环境:预编译+编译+汇编+链接详解

目录 翻译环境和运行环境 翻译环境 预处理&#xff08;预编译&#xff09; 编译 词法分析 语法分析 语义分析 汇编 链接 运行环境 ⭐翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被…

Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析

本文概要 AtomicIntegerFieldUpdater类提供了一种高效、简洁的方式来原子性地更新对象的volatile字段&#xff0c;无需使用重量级的锁机制&#xff0c;它通过基于反射的API实现了细粒度的并发控制&#xff0c;提升了多线程环境下的性能表现。 AtomicIntegerFieldUpdater核心概…

选择VR全景行业,需要了解哪些内容?

近年来&#xff0c;随着虚拟现实、增强现实等技术的持续发展&#xff0c;VR全景消费市场得以稳步扩张。其次&#xff0c;元宇宙行业的高速发展&#xff0c;也在进一步拉动VR全景技术的持续进步&#xff0c;带动VR产业的高质量发展。作为一种战略性的新兴产业&#xff0c;国家和…

【vue vue-seamless-scroll】解决vue-seamless-scroll鼠标悬浮才滚动或者只滚动一次就失效的问题

解决问题&#xff1a;使用vue-seamless-scroll发现只有鼠标悬浮上去才滚动&#xff0c;而且滚动一次停止了 目标效果&#xff1a; 解决方案&#xff1a; 最后发现是因为数据需要在页面挂载好就赋值&#xff0c;否则页面在加载完成后&#xff0c;数据无法自动滚动。但因为数据…

防火墙内容安全笔记

目录 DFI和DPI IDS和IPS 签名 AV URL过滤 HTTPS过滤 内容过滤 文件类型过滤 文件内容过滤 邮件过滤 VPN概述 DFI和DPI DFI和DPI技术 --- 深度检测技术 DPI DPI --- 深度包检测技术 --- 主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#…

百亿美金的设计,深度剖析 GitLab 的 Postgres 数据库 schema

原文链接 这篇文章写于 2022 年&#xff0c;前一年 GitLab 刚好完成 IPO。目前 GitLab 市值超过 100 亿美金&#xff0c;它的所有收入都来源于同名产品 GitLab&#xff0c;而这篇文章就是全面分析 GitLab 这个产品的数据库 schema。 我花了一些时间研究 GitLab 的 Postgres sch…

【ArcGIS Pro二次开发】(82):玩个花活_控规指标块生成

一、要实现的效果 废话不多说&#xff0c;这次要实现的是类似控规指标块的标注&#xff1a; 这里只是示例&#xff0c;用了5个格子&#xff0c;做成9个格子也是可以的。 实现这个效果最关键的是要用到Pro中的复合标注。 关于复合标注的用法可以搜一下帮助里的【使用复合注释…

网站常见的攻击类型有什么,如何针对性防护

在互联网时代&#xff0c;几乎每个网站都存在着潜在的安全威胁。这些威胁可能来自人为失误&#xff0c;也可能源自网络犯罪团伙所发起的复杂攻击。无论攻击的本质如何&#xff0c;网络攻击者的主要动机通常是谋求经济利益。这意味着不管是什么网站类型潜在的威胁一直都存在。 在…

关于2025年的AMC8竞赛,你可能感兴趣的一些问题和信息

最近几天&#xff0c;我分享了一些历年的AMC8数学竞赛真题和解析&#xff0c;有一些家长和孩子第一次接触&#xff0c;产生了浓厚的兴趣&#xff0c;并且问了许多关于AMC8的问题。为了帮助更多家长和孩子了解这个比赛&#xff0c;我把常见的问题&#xff0c;以及大家可能感兴趣…