k8s网络之Calico网络


Calico 是一种容器之间互通的网络方案。在虚拟化平台中,比如 OpenStack、Docker 等都需要实现 workloads 之间互连,但同时也需要对容器做隔离控制,就像在 Internet 中的服务仅开放80端口、公有云的多租户一样,提供隔离和管控机制。

而在多数的虚拟化平台实现中,通常都使用二层隔离技术来实现容器的网络,这些二层的技术有一些弊端,比如需要依赖 VLAN、bridge 和隧道等技术,

其中 bridge 带来了复杂性,vlan 隔离和 tunnel 隧道则消耗更多的资源并对物理环境有要求,随着网络规模的增大,整体会变得越加复杂。

我们尝试把 Host 当作 Internet 中的路由器,同样使用 BGP 同步路由,并使用 iptables 来做安全访问策略,最终设计出了 Calico 方案。

  

适用场景:k8s环境中的pod之间需要隔离

设计思想:Calico 不使用隧道或 NAT 来实现转发,而是巧妙的把所有二三层流量转换成三层流量,并通过 host 上路由配置完成跨 Host 转发。

设计优势

1.更优的资源利用

二层网络通讯需要依赖广播消息机制,广播消息的开销与 host 的数量呈指数级增长,Calico 使用的三层路由方法,则完全抑制了二层广播,减少了资源开销。

另外,二层网络使用 VLAN 隔离技术,天生有 4096 个规格限制,即便可以使用 vxlan 解决,但 vxlan 又带来了隧道开销的新问题。而 Calico 不使用 vlan 或 vxlan 技术,使资源利用率更高。

2.可扩展性

Calico 使用与 Internet 类似的方案,Internet 的网络比任何数据中心都大,Calico 同样天然具有可扩展性。

3.简单而更容易 debug

因为没有隧道,意味着 workloads 之间路径更短更简单,配置更少,在 host 上更容易进行 debug 调试。

4.更少的依赖

Calico 仅依赖三层路由可达。

5.可适配性

Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。

 Calico 是一个三层的数据中心网络方案,而且方便集成 OpenStack 这种 IaaS 云架构,能够提供高效可控的 VM、容器、裸机之间的通信。

Calico不使用重叠网络比如flannel和libnetwork重叠网络驱动,它是一个纯三层的方法,使用虚拟路由代替虚拟交换,每一台虚拟路由通过BGP协议传播可达信息(路由)到剩余数据中心;Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,

而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。

缺陷

从上面的通信过程来看,跨主机通信时,整个通信路径完全没有使用NAT或者UDP封装,性能上的损耗确实比较低。但正式由于calico的通信机制是完全基于三层的,这种机制也带来了一些缺陷,例如:

  • calico目前只支持TCP、UDP、ICMP、ICMPv6协议,如果使用其他四层协议(例如NetBIOS协议),建议使用weave、原生overlay等其他overlay网络实现。
  • 基于三层实现通信,在二层上没有任何加密包装,因此只能在私有的可靠网络上使用。
  • 流量隔离基于iptables实现,并且从etcd中获取需要生成的隔离规则,有一些性能上的隐患

 

结合上面这张图,我们来过一遍 Calico 的核心组件:

 

 

 

 

 

                                                          

 

 

Felix:主要的Calico代理agent Calico agent,跑在每台需要运行 workload 的节点上,主要负责配置路由及 ACLs 等信息来确保 endpoint 的连通状态

Felix是一个守护程序,它在每个提供endpoints资源的计算机上运行。在大多数情况下,这意味着它需要在托管容器或VM的宿主机节点上运行。 Felix 负责编制路由和ACL规则以及在该主机上所需的任何其他内容,以便为该主机上的endpoints资源正常运行提供所需的网络连接。

根据特定的编排环境,Felix负责以下任务:

管理网络接口,Felix将有关接口的一些信息编程到内核中,以使内核能够正确处理该endpoint发出的流量。 特别是,它将确保主机正确响应来自每个工作负载的ARP请求,并将为其管理的接口启用IP转发支持。它还监视网络接口的出现和消失,以便确保针对这些接口的编程得到了正确的应用。
编写路由,Felix负责将到其主机上endpoints的路由编写到Linux内核FIB(转发信息库)中。 这可以确保那些发往目标主机的endpoints的数据包被正确地转发。
编写ACLs,Felix还负责将ACLs编程到Linux内核中。 这些ACLs用于确保只能在endpoints之间发送有效的网络流量,并确保endpoints无法绕过Calico的安全措施。
报告状态,Felix负责提供有关网络健康状况的数据。 特别是,它将报告配置其主机时发生的错误和问题。 该数据会被写入etcd,以使其对网络中的其他组件和操作才可见。
Orchestrator Plugin

每个主要的云编排平台都有单独的Calico网络插件(例如OpenStack,Kubernetes)。 这些插件的目的是将Calico更紧密地绑定到编排工具中,允许用户管理Calico网络,就像他们管理编排工具中内置的网络工具一样。

一个好的Orchestrator插件示例是Calico Neutron ML2 驱动程序。 该插件与Neutron的ML2插件集成,允许用户通过Neutron API调用来配置Calico网络,实现了与Neutron的无缝集成。

Orchestrator插件负责以下任务:

API Translation,每个云编排工具都不可避免地拥有自己的一套用于管理网络的API接口规范, Orchestrator插件的主要工作就是将这些API转换为Calico的数据模型,然后将其存储在Calico的数据存储区中。这种转换中的一些工作将非常简单,其他一部分可能更复杂,以便将单个复杂操作(例如,实时迁移)转换为Calico网络期望的一系列更简单的操作。
Feedback,如有需要,orchestrator插件将从Calico网络向编排器提供管理命令的反馈信息。 包括提供有关Felix存活的信息,以及如果网络配置失败则将某些endpoints标记为失败。
ETCD: 分布式键值存储,主要负责网络元数据一致性,确保 Calico 网络状态的准确性

etcd是一个分布式键值存储数据库,专注于实现数据存储一致性。 Calico使用etcd提供组件之间的数据通信,并作为可以保证一致性的数据存储,以确保Calico始终可以构建出一个准确的网络。

根据orchestrator插件的不同,etcd既可以是作为主数据存储使用,也可以是一个单独数据存储的轻量级镜像。例如,在OpenStack部署中,OpenStack数据库被认为是“真实配置信息的来源”,而etcd用于镜像其中有关网络配置的信息,并用于服务其他Calico组件。

etcd组件穿插在整个部署中。它可以被分为两组主机节点:核心集群和代理。

对于小型部署,核心集群可以是一个节点的etcd集群(通常与orchestrator插件组件位于同一节点上)。这种部署模型很简单但没有为etcd提供冗余。在etcd失败的情况下,orchstrator插件必须重建数据库,例如OpenStack,它需要插件从OpenStack数据库重新同步状态到etcd。

在较大的部署中,核心群集可以根据etcd管理指南进行扩展。

此外,在运行Felix或orchstrator插件的每台计算机上,会运行一个etcd代理服务。这减少了etcd核心集群上的负载,并为主机节点屏蔽了etcd服务集群的细节。在etcd集群与orchstrator插件在同一台机器上都有成员的情况下,可以放弃在该机器上使用etcd代理。

etcd负责执行以下任务:

Data Storage,etcd以分布式、一致和容错的方式存储Calico网络的数据(对于至少三个etcd节点的cluster大小)。 这确保Calico网络始终处于已知良好状态,同时允许运行etcd的个别机器节点失败或无法访问。Calico网络数据的这种分布式存储提高了Calico组件从数据库读取的能力。
Communication,etcd也用作组件之间的通信服务。 我们通过让非etcd组件监视键值空间中的某些点来确保他们看到已经做出的任何更改,从而允许他们及时响应这些更改。 该功能允许将状态信息提交到数据库,然后触发基于该状态数据的进一步网络配置管理。

 

BIRD是什么

BIRD是布拉格查理大学数学与物理学院的一个学校项目,项目名是BIRD Internet Routing Daemon的缩写。 目前,它由CZ.NIC实验室开发和支持。

BIRD项目旨在开发一个功能齐全的动态IP路由守护进程,主要针对(但不限于)Linux,FreeBSD和其他类UNIX系统,并在GNU通用公共许可证下分发。详细信息参照官网https://bird.network.cz/。

作为一个开源的网络路由守护进程项目,BRID设计并支持了以下功能:

both IPv4 and IPv6 protocols
multiple routing tables
the Border Gateway Protocol (BGPv4)
the Routing Information Protocol (RIPv2, RIPng)
the Open Shortest Path First protocol (OSPFv2, OSPFv3)
the Babel Routing Protocol
the Router Advertisements for IPv6 hosts
a virtual protocol for exchange of routes between different routing tables on a single host
a command-line interface allowing on-line control and inspection of status of the daemon
soft reconfiguration (no need to use complex online commands to change the configuration, just edit the configuration file and notify BIRD to re-read it and it will smoothly switch itself to the new configuration, not disturbing routing protocols unless they are affected by the configuration changes)
a powerful language for route filtering

BGP Client (BIRD): 主要负责把 Felix 写入 kernel 的路由信息分发到当前 Calico 网络,确保 workload 间的通信的有效性

Calico在每个运行Felix服务的节点上都部署一个BGP客户端。 BGP客户端的作用是读取Felix程序编写到内核中并在数据中心内分发的路由信息。

BGP客户端负责执行以下任务:

路由信息分发,当Felix将路由插入Linux内核FIB时,BGP客户端将接收它们并将它们分发到集群中的其他工作节点。
BGP Route Reflector (BIRD) : 大规模部署时使用,摒弃所有节点互联的 mesh 模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发

对于较大规模的部署,简单的BGP可能成为限制因素,因为它要求每个BGP客户端连接到网状拓扑中的每一个其他BGP客户端。这需要越来越多的连接,迅速变得难以维护,甚至会让一些设备的路由表撑满。

因此,在较大规模的部署中,Calico建议部署BGP Route Reflector。通常是在Internet中使用这样的组件充当BGP客户端连接的中心点,从而防止它们需要与群集中的每个BGP客户端进行通信。为了实现冗余,也可以同时部署多个BGP Route Reflector服务。Route Reflector仅仅是协助管理BGP网络,并没有endpoint数据会通过它们。

在Calico中,此BGP组件也是使用的最常见的BIRD,配置为Route Reflector运行,而不是标准BGP客户端。

BGP Route Reflector负责以下任务:

集中式的路由信息分发,当Calico BGP客户端将路由从其FIB通告到Route Reflector时,Route Reflector会将这些路由通告给部署集群中的其他节点。

总结:

     利用了Linux内核原生的路由和iptables防火墙功能。 进出各个容器、虚拟机和物理主机的所有流量都会在路由到目标之前遍历这些内核规则。

  • Felix:主要的Calico代理agent,运行每台计算机上管理endpoints资源。
  • calicoctl:允许从命令行界面配置实现高级策略和网络。
  • orchestrator plugins:提供与各种流行的云计算编排工具的紧密集成和同步支持。
  • key/value store:存储Calico的策略配置和网络状态信息,目前主要使用etcdv3或k8s api。
  • calico/node:在每个主机上运行,从key/value存储中读取相关的策略和网络配置信息,并在Linux内核中实现它。
  • Dikastes/Envoy:可选的Kubernetes sidecars,可以通过相互TLS身份验证保护工作负载到工作负载的通信,并增加应用层控制策略。

通过将整个互联网的可扩展 IP 网络原则压缩到数据中心级别,Calico 在每一个计算节点利用Linux kernel实现了一个高效的vRouter来负责数据转发而每个vRouter通过BGP

协议负责把自己上运行的 workload 的路由信息像整个 Calico 网络内传播 - 小规模部署可以直接互联,大规模下可通过指定的BGP route reflector 来完成。这样保证最终所有的 workload 之间的数据流量都是通过 IP 包的方式完成互联的

Calico原理

Calico把每个操作系统的协议栈认为是一个路由器,然后把所有的容器认为是连在这个路由器上的网络终端,在路由器之间跑标准的路由协议——BGP的协议,然后让它们自己去学习这个网络拓扑该如何转发。

所以Calico方案其实是一个纯三层的方案,也就是说让每台机器的协议栈的三层去确保两个容器,跨主机容器之间的三层连通性。

对于控制平面,它每个节点上会运行两个主要的程序,一个是Felix,它会监听ECTD中心的存储,从它获取事件,比如说用户在这台机器上加了一个IP,或者是分配了一个容器等。接着会在这台机器上创建出一个容器,并将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。

绿色部分是一个标准的路由程序,

它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,你们路由的时候得到这里来。

由于Calico是一种纯三层的实现,因此可以避免与二层方案相关的数据包封装的操作,中间没有任何的NAT,没有任何的overlay,所以它的转发效率可能是所有方案中最高的,因为它的包直接走原生TCP/IP的协议栈,它的隔离也因为这个栈而变得好做

因为TCP/IP的协议栈提供了一整套的防火墙的规则,所以它可以通过IPTABLES的规则达到比较复杂的隔离逻辑。

 

 

 

 

 Calico 节点组网可以直接利用数据中心的网络结构(支持 L2 或者 L3),不需要额外的 NAT,隧道或者 VXLAN overlay network。

 

如上图所示,这样保证这个方案的简单可控,而且没有封包解包,节约 CPU 计算资源的同时,提高了整个网络的性能。

此外,Calico 基于 iptables 还提供了丰富而灵活的网络 policy, 保证通过各个节点上的 ACLs 来提供 workload 的多租户隔离、安全组以及其他可达性限制等功能。

在主机网络拓扑的组织上,calico的理念与weave类似,都是在主机上启动虚拟机路由器,将每个主机作为路由器使用,组成互联互通的网络拓扑。当安装了calico的主机组成集群后

其拓扑如下图所示

 

 

 

每个主机上都部署了calico/node作为虚拟路由器,并且可以通过calico将宿主机组织成任意的拓扑集群。当集群中的容器需要与外界通信时,就可以通过BGP协议将网关物理路由器加入到集群中,使外界可以直接访问容器IP,而不需要做任何NAT之类的复杂操作。

当容器通过calico进行跨主机通信时,其网络通信模型如下图所示:

 

 

 

 

 

 

从上图可以看出,当容器创建时,calico为容器生成veth pair,一端作为容器网卡加入到容器的网络命名空间,并设置IP和掩码,一端直接暴露在宿主机上,并通过设置路由规则,将容器IP暴露到宿主机的通信路由上。

于此同时,calico为每个主机分配了一段子网作为容器可分配的IP范围,这样就可以根据子网的CIDR为每个主机生成比较固定的路由规则。

当容器需要跨主机通信时,主要经过下面的简单步骤:

  • 容器流量通过veth pair到达宿主机的网络命名空间上。
  • 根据容器要访问的IP所在的子网CIDR和主机上的路由规则,找到下一跳要到达的宿主机IP。
  • 流量到达下一跳的宿主机后,根据当前宿主机上的路由规则,直接到达对端容器的veth pair插在宿主机的一端,最终进入容器。

 

 

 

 

 

 

Calico网络方式(两种)

路由表中Flags标志的含义:

U up表示当前为启动状态

H host表示该路由为一个主机,多为达到数据包的路由

G Gateway 表示该路由是一个网关,如果没有说明目的地是直连的

D Dynamicaly 表示该路由是重定向报文修改

M 表示该路由已被重定向报文修改


1)IPIP
从字面来理解,就是把一个IP数据包又套在一个IP包里,即把 IP 层封装到 IP 层的一个 tunnel,看起来似乎是浪费,实则不然。它的作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。ipip 的源代码在内核 net/ipv4/ipip.c 中可以找到。

  • IPIP是一种将各Node的路由之间做一个tunnel,再把两个网络连接起来的模式。启用IPIP模式时,Calico将在各Node上创建一个名为”tunl0″的虚拟网络接口。如下图所示。

 

 

 

使用IPIP模式后的路由如下:

2)BGP
边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单IP,BGP 机房的优点:服务器只需要设置一个IP地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。

 前面介绍过IPIP网络pod之间的流量发送tunl0,然后tunl0发送对端设备。BGP网络中,pod之间的流量直接从网卡发送目的地,减少了tunl0这个环节。

 

IPIP网络

流量:tunlo设备封装数据,形成隧道,承载流量。

适用网络类型:适用于互相访问的pod不在同一个网段中,跨网段访问的场景。外层封装的ip能够解决跨网段的路由问题。

效率:流量需要tunl0设备封装,效率略低

BGP网络

流量:使用路由信息导向流量

适用网络类型:适用于互相访问的pod在同一个网段,适用于大型网络。

效率:原生hostGW,效率高

部署calico提供网络策略功能

官方提供的安装方式

https://docs.projectcalico.org/getting-started/kubernetes/installation/config-options

 

 

 

 

 

 

 这两说一下ETCD 的安装流程,不推荐这种方式

规模小于50 的节点可以考虑

etcd  适合混合部署的环境

大概安装流程:

curl https://docs.projectcalico.org/manifests/calico-etcd.yaml -O

修改kubelet配置:

设置各node上Kubelet服务的启动参数: --network-plugin=cni, 可能还要加上这两个参数:

 --cni-conf-dir  CNI插件的配置文件目录,默认为/etc/cni/net.d 该目录下的配置文件内容需要符合CNI规范

 --cni-bin-dir: CNI插件的可执行文件目录,默认为/opt/cni/bin

 设置好后,重新启动kubelet。

这样通过calico就完成了Node间容器网络的设置 ,在后续的pod创建过程中,Kubelet将通过CNI接口调用 calico进行Pod的网络设置包括IP地址,路由规则,Iptables规则 

Secret 配置修改
data:
etcd-key: (cat /opt/kubernetes/ssl/server-key.pem | base64 -w 0) # 将输出结果填写在这里
etcd-cert: (cat /opt/kubernetes/ssl/server.pem | base64 -w 0) # 将输出结果填写在这里
etcd-ca: (cat /opt/kubernetes/ssl/ca.pem | base64 -w 0) # 将输出结果填写在这里

ConfigMap 配置修改
data:
etcd_endpoints: "https://192.168.0.216:2379"
etcd_ca: "/calico-secrets/etcd-ca"
etcd_cert: "/calico-secrets/etcd-cert"
etcd_key: "/calico-secrets/etcd-key"

 

 

 

关于ConfigMap部分主要参数如下:
etcd_endpoints:Calico使用etcd来保存网络拓扑和状态,该参数指定etcd的地址,可以使用K8S Master所用的etcd,也可以另外搭建。
calico_backend:Calico的后端,默认为bird。
cni_network_config:符合CNI规范的网络配置,其中type=calico表示,Kubelet 从 CNI_PATH (默认为/opt/cni/bin)目录找calico的可执行文件,用于容器IP地址的分配。
etcd 如果配置TLS安全认证,则还需要指定相应的ca、cert、key等文件

修改 Pods 使用的 IP 网段,默认使用 192.168.0.0/16 网段

 

 

 

Calico 模式设置

Calico 有两种网络模式:BGP 和 IPIP

  • 使用 IPIP 模式时,设置 CALICO_IPV4POOL_IPIP="always"
  • 使用 BGP 模式时,设置 CALICO_IPV4POOL_IPIP="off"

kubectl apply -f calico-etcd.yaml

 

 

 

二进制安装calicoctl,部署到一台主master节点即可

 

官网安装方式:

https://docs.projectcalico.org/getting-started/clis/calicoctl/install

 

https://github.com/projectcalico/calicoctl/releases

wget  https://github.com/projectcalico/calicoctl/releases/download/v3.14.2/calicoctl-linux-amd64  -O /usr/bin/calicoctl

chmod +x /usr/bin/calicoctl

calicoctl通过读写calico的数据存储系统(datastore)进行查看或者其他各类管理操作,通常,它需要提供认证信息经由相应的数据存储完成认证。
在使用Kubernetes API数据存储时,需要使用类似kubectl的认证信息完成认证。它可以通过环境变量声明的DATASTORE_TYPE和KUBECONFIG接入集群,
例如以下命令格式运行calicoctl

calicoctl create:根据配置文件创建资源,配置文件可以是yaml或者json格式,资源类型node、bgpPeer、hostEndpoint、workloadEndpoint、ipPool、policy、profile。-f 指定资源文件位置,-c 默认是/etc/calico/calicoctl.cfg
calicoctl replace:根据配置文件替换一个已经存在的资源,参数和create一样
calicoctl apply:根据配置文件创建一个资源或者替换一个已有的资源,参数和create一样
calicoctl delete:根据资源文件删除资源,或者根据类型、标识符删除资源
calicoctl get:根据文件显示设置资源,或者根据类型、标识符显示资源。显示格式有多种ps、wide、yaml、json....
calicoctl config:允许用户查看或者修改Felix和BGP的低级组件配置。calicoctl config set/unset/get <NAME> <VALUE>
calicoctl ipam release:从calico ip 地址管理中释放一个ip。这个不会删除endpoint上的ip,只是会清除已经释放的美欧干净移除的ip
calicoctl ipam show:显示已经已经分配的ip

官网配置和使用说明

https://docs.projectcalico.org/getting-started/clis/calicoctl/configure/kdd


[root@k8s-master ~]# DATASTORE_TYPE=kubernetes KUBECONFIG=~/.kube/config calicoctl get nodes
NAME
k8s-master
k8s-node1
k8s-node2
也可以直接将认证信息等保存于配置文件中,calicoctl默认加载 /etc/calico/calicoctl.cfg 配置文件读取配置信息,如下所示:
[root@k8s-master ~]# cat /etc/calico/calicoctl.cfg
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
     datastoreType: "kubernetes"
     kubeconfig: "/root/.kube/config"
[root@k8s-master ~]# calicoctl get nodes
NAME
k8s-master
k8s-node1
k8s-node2
[root@k8s-master ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+---------------+-------------------+-------+----------+-------------+
| 138.138.82.15 | node-to-node mesh | up | 09:03:56 | Established |
| 138.138.82.16 | node-to-node mesh | up | 09:04:08 | Established |
+---------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.
[root@k8s-master ~]# calicoctl get ipPool -o yaml

 #查看工作中的负载节点

[root@k8s-master ~]# calicoctl get workloadendpoints

如果遇到问题可以使用calicoctl命令行工具收集诊断信息。这应该以超级用户权限运行,例如:
# calicoctl node diags

需要注意的问题:如果服务器的网卡名称不一样,需要固定指定的网卡,或者IP 网络
- name: IP_AUTODETECTION_METHOD
  value: "interface=eno2.*"
#value: "can-reach=192.168.1.1"
经过测试calico 会按照ifconfig 倒序的方式查找第一个可以通的网卡地址,正好和flannel相反

 

 

 

详细的文档参考

https://www.dazhuanlan.com/2019/11/28/5ddf4e436e79f/

https://zhuanlan.zhihu.com/p/81120952

本文参考文档:

https://www.cnblogs.com/centos-python/articles/10876083.html

https://www.kubernetes.org.cn/4960.html

https://cloud.tencent.com/developer/article/1482739


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM