java系统找不到指定文件怎么解决
234
2022-10-11
容器服务 TKE 存储插件与云硬盘 CBS 最佳实践应用
引言
随着自研上云的深入,越来越多的有状态服务对于在 TKE 集群中使用云上存储能力的需求也越来越强烈。
目前腾讯云容器服务 TKE(Tencent Kubernetes Engine)已支持在 TKE 集群中的应用使用多种存储服务,包括云硬盘 CBS、文件存储 CFS以及对象存储 COS。TKE 通过两种存储插件(In-Tree 和 CSI)来支持上述能力,用户可以通过云控制台很方便地选择存储类型并创建对应的 PV/PVC。但仍然会有一些问题困扰着大家,比如:TKE 集群中是否支持扩容 CBS 云盘;如果集群跨可用区,如何避免集群中频繁出现挂载(attach)失败;TKE 中是否支持快照功能;我的应用应该选择哪种类型存储;In-Tree 和 CSI 都支持 CBS,二者有和区别,是否能把之前使用 In-Tree 插件创建的云盘转变为 CSI 插件管理等。
对于 TKE 存储的相关问题,这里会详细介绍。接下来,我们先概览下 Kubernetes 持久化存储的流程
Kubernetes 持久化存储流程
这里对 Kubernetes 持久化存储的流程做个概览,不深入各个组件。
创建一个使用了持久化存储的 pod 的流程包含以下步骤:
用户创建一个引用PVC的 pod(动态创建PV); Scheduler根据 pod 的配置、节点状态、PV 配置等其他因素把 pod 调度到一个合适的 node 上; PV Controller watch 到 PVC,调用 Volume Plugin 去创建 PV,并绑定 PV 和 PVC。如果是 out-of-tree 存储插件(如 CSI),则创建 PV 实际是由 external provisioner 完成,之后 PV Controller 完成 PV 和 PVC 的bound;如果是 in-tree 插件,但是通过kubernetes-sigs/sig-storage-lib-external-provisioner实现了一个 external provisioner,则与 out-of-tree 插件相同;如果是 in-tree 插件,且插件直接实现了相应的创删接口,则 PV Controller 直接调用 in-tree 插件的实现完成创建 PV。 AD Controller 对比 asw 和 dsw 状态,发现 Volume 需要被 attach,则调用 Volume Plugin 的实现去 attach。in-tree 插件不需多说,如果是 CSI 插件,则 AD Controller 会先调用 CSI in-tree 代码创建 VolumeAttachment 对象,CSI 插件的一个名为 external-attacher 的 sidecar 会 watch 该对象,watch 到创建则调用 CSI driver 的相应方法(ControllerPublishVolume)来 attach。 VolumeManager 等到 volume 成功 attach 到节点后,开始调用 Volume Plugin 去进行 mount 操作。这个mount 操作分为两步:第一步是格式化设备并把 volume mount 到一个 global mount path(/var/lib/kubelet/plugins下),第二步是将 bind mount 刚才的 global mount path到/var/lib/kubelet/pods/${pod_UUID}/volumes下。 Kubelet 调用容器运行时启动容器,并且 bind mount 第5步中的 mount path 到容器中。
(Provision -> Attach -> Mount; Unmount -> Detach -> Delete)
TKE 存储插件及原理介绍
随着 Kubernetes 社区发展,TKE 先后支持了 In-Tree 和 CSI 两种存储插件。二者在功能上的主要区别在于 In-Tree 存储插件仅支持在 TKE 集群使用 CBS,而 CSI 支持使用 CBS、CFS、COS。
类型 | 支持CBS | 支持CFS | 支持COS | 参考 |
---|---|---|---|---|
In-Tree | √ | × | × | |
CSI | √ | √ | √ | https://github.com/TencentCloud/kubernetes-csi-tencentcloud |
In-Tree 插件(QcloudCbs)
kubernetes 早期只支持以 In-Tree 的方式扩展存储插件,也就是插件在 Kubernetes 代码中实现。 In-Tree 插件名为cloud.tencent.com/qcloud-cbs,所以也可称为 QcloudCbs,在 TKE 集群中有个默认的名为cbs的 StorageClass。
NAME PROVISIONER AGE cbs (default) cloud.tencent.com/qcloud-cbs 48m
特性
In-Tree 插件只实现了使用 CBS 的能力,其主要特性有:
静态数据卷:即用户手动创建 volme、PV 对象、PVC 对象 动态数据卷:根据 StorageClass 配置来由插件控制创建和删除 volume 和 PV 拓扑感知:CBS 不支持跨可用区挂载,在多可用区集群中,会先调度 pod,然后去调度后的 node 的 zone 创建 volume。 调度器感知节点 maxAttachLimit:腾讯云单个 CVM 上默认最多挂载 20块 CBS 盘,调度器感知该限制,调度时过滤到要超过 maxAttachLimit 的节点。可以全局修改 maxAttachLimit,但需要 IaaS 层先支持。
腾讯云存储 | 静态数据卷 | 动态数据卷 | 拓扑感知 | 调度器感知节点 maxAttachLimit |
---|---|---|---|---|
腾讯云硬盘(CBS) | 支持两种使用方式: | 支持 | 支持。pod 调度后,在同一个可用区创建 volume。避免 CBS 跨可用区无法使用。 | 支持。云服务器(cvm)可以挂载的云硬盘(cbs)是有上限的。调度器调度 pod 时过滤掉超过最大可挂载 CBS 数量的节点。 |
原理简介
下面简单了解下 In-Tree 插件 QcloudCbs 的架构图,了解各相关组件分别完成何种工作。
上图是包含 TKE In-Tree 存储插件的 Kubernetes 存储架构图。图中绿色部分,皆属于 In-Tree 插件 QcloudCbs 的实现范畴。由上述的 Kubernetes持久化存储流程 可知要动态使用一个 cbs pv,主要有三个过程:provision、attach、mount,而这三个过程是由不同组件负责的:
cbs-provisioner 负责 volume 的 provision/delete。为了与 Kubernetes 代码解耦,cbs-provisioner 是基于kubernetes-sigs/sig-storage-lib-external-provisioner实现的一个 external provisioner,来 provision 和 delete volume。PV Controller 在这种模式下虽然不去 provision/delete volume,但是还是会参与处理(比如 PV 和 PVC 的绑定)。 AD Controller 负责 volume 的 attach/detach。Tencent Cloud Provider 中封装云 API,In-Tree 插件调用 Cloud Provider 实现了 attach/detach 的具体逻辑,并提供给 AD Controller 调用。 kubelet 的 Volume Manager 负责 volume 的 mount/unmount。In-Tree 插件中实现 MountDevice、SetUp 等接口,Volume Manager 调用其完成准备 volume 的最后一步。 另外,Scheduler 中也有 volume 相关的逻辑,我们添加了一个 predicate 策略:MaxQcloudCbsVolumeCount,该策略主要实现调度器感知节点 maxAttachLimit特性。而 Scheduler 原生的一个 predicate 策略:NoVolumeZoneConflictPred,是用来把 pod 调度到已有 PV 所在 zone 的节点,这可以避免云盘跨可用区挂载的问题;对于新建 PV 的话,避免云盘跨可用区挂载问题则由拓扑感知特性完成。
CSI 插件
CSI 是 Kubernetes 社区扩展卷的标准和推荐方式。TKE 的 CSI 插件包含 CBS、CFS、COS 三个 driver,本节重点介绍 CBS CSI driver,并与 QcloudCbs 进行对比。3个 driver 的静态 pv 和动态 pv 的支持情况如下表所示:
腾讯云存储 | 静态数据卷 | 动态数据卷 |
---|---|---|
云硬盘(CBS) | 支持 | 支持 |
文件存储(CFS) | 支持 | 支持 |
对象存储(COS) | 支持 | 不支持 |
CBS CSI 特性及与 QcloudCbs 对比
CBS CSI 比 QcloudCbs 多几个特性:volume 在线扩容,volume 快照和恢复。
存储插件 | 静态数据卷 | 动态数据卷 | 拓扑感知 | 调度器感知节点maxAttachLimit | 卷在线扩容 | 卷快照&恢复 |
---|---|---|---|---|---|---|
CBS CSI | √ | √ | √ | √ | √ | √ |
QcloudCbs(In-Tree) | √ | √ | √ | √ | × | × |
原理简介
CSI 原理简介
CSI 原理参考上图。要实现一个 CSI driver,一般需要实现以下 3 个 gRPC services(CSI Controller Service 可选):
CSI Identity Services:提供 driver 信息(drivername,版本等) CSI Controller Services (可选):controller 负责创删卷、attach/detach、扩容、快照等。涉及的方法如下: CreateVolume/DeleteVolume Controller[Publish|Unpublish]Volume (对应attach/detach) CreateSnapshot/DeleteSnapshot/ListSnapshots ControllerExpandVolume CSI Node Services :负责向节点注册 driver,mount/unmount。涉及的方法如下: NodeStageVolume/NodeUnstageVolume((un)mount device) NodePublishVolume/NodeUpPublishVolume((un)mount volume)
在我们实现之外,kuberntes Team 还提供了多个外部组件,用于沟通 k8s 原生组件(apiserver、controller manager、kubelet)与自己实现的 CSI driver。
external-provisioner:watch PersistentVolumeClaim(PVC)对象,调用 driver 的CreateVolume/DeleteVolume external-attacher:watch VolumeAttachment对象,调用 driver 的Controller[Publish|Unpublish]Volume external-resizer: watch PersistentVolumeClaim对象,调用 driver 的ControllerExpandVolume external-snapshotter和snapshot-controller:snapshot-controller watch VolumeSnapshot和VolumeSnapshotContent CRD 对象,external-snapshotter watch VolumeSnapshotContent对象。调用 driver 的CreateSnapshot/DeleteSnapshot/ListSnapshots node-driver-registrar\:使用NodeGetInfo获取 driver 信息,然后使用 kubelet 插件注册机制注册 driver。
CBS CSI 部署图
CBS CSI 使用社区推荐部署方式,包含两个 workload:
一个 DaemonSet,也就是每个 Node 会有一个,我们可以简单称为NodePlugin,由 CBS CSI Driver 和 node-driver-registrar 两个容器组成。负责向节点注册 driver,并提供 mount 的能力。 一个 StatefulSet/Deployment,我们可以简称为Controller。由 driver 和多个 sidecar(external-provisioner、external-attacher、external-resizer、external-snapshotter、snapshot-controller)一起构成,提供创删卷、attach/detach、扩容、快照等能力
CBS CSI 插件的 mount 是 driver 容器执行的,它是如何 mount 到 Node 上的?
使用推荐
TKE 集群版本为 1.14+(包含 1.14),推荐使用 CSI 插件 需要在TKE集群中使用 CFS 和 COS 能力,使用 CSI 插件 需要在TKE集群中对 CBS 盘在线扩容和使用快照功能,使用 CSI 插件 已经使用了 QcloudCbs(In-Tree 插件)的,可以继续使用。(后续会通过 Volume Migration 统一到 CBS CSI)
最佳实践
provisioner:
cbs csi —— "com.tencent.cloud.csi.cbs" cbs intree —— "cloud.tencent.com/qcloud-cbs"
cbs csi 的安装请参见 cbs csi 文档,我们也已经在腾讯云控制台支持扩展组件安装。
本节最佳实践均以 cbs csi 插件为例,相应版本要求也是针对 cbs csi 插件。
1、如果集群节点跨 zone,如何避免 cbs 云盘跨可用区挂载?
cbs 云盘不支持跨可用区挂载到节点,所以在跨可用区的集群中推荐通过拓扑感知特性来避免跨可用区挂载的问题。
1.1 使用前注意
TKE集群版本 >= 1.14 确保 csi 插件为最新版本
1.2 如何使用
使用方式很简单,在 storageclass 中设置 volumeBindingMode为WaitForFirstConsumer,然后使用该 storageClass 即可。intree 和 csi 插件均支持。
kind: StorageClass metadata: name: cbs-topo parameters: type: cbs provisioner: com.tencent.cloud.csi.cbs reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer
1.3 原理
拓扑感知调度需要多个 k8s 组件配合完成,包括 scheduler、pv controller、external-provisioner。流程为:
pv controller watch 到 PVC 对象,发现 storageclass 的 volumeBindingMode 为WaitForFirstConsumer,即不会马上处理该pvc的创建事件,等待 scheduler 处理; scheduler 调度完 pod 后,会将 nodeName 以 annotation 的方式打到 PVC 对象上: volume.kubernetes.io/selected-node: 10.0.0.72 pv controller 获取到 PVC 对象的更新事件后,处理这个 annotation(volume.kubernetes.io/selected-node),根据 nodeName 获取 Node 对象,传入到 provisioner 中。 provisioner 根据传过来的 Node 对象的 label 获取可用区(failure-domain.beta.kubernetes.io/zone),之后在对应 zone 创建 pv,从而达到和 pod 相同可用区的效果,避免云盘和 node 在不同可用区而无法挂载。
2、如何在线扩容云盘?
TKE 支持在线扩容 PV,对应的云盘及文件系统,即不需要重启 pod 即可完成扩容。但,为了确保文件系统的稳定性,还是推荐先让云盘文件系统处于未 mount 情况下。为此,我们将提供两种扩容方式:
不重启 pod 的情况下在线扩容 这种情况下被扩容的云盘的文件系统被 mount 在节点上,如果 I/O 的话,有可能会出现文件系统扩容错误 重启 pod 的情况下在线扩容 这种情况下被扩容的云盘的文件系统被 unmount了。可以避免上面的问题,推荐这种方式。
2.1 使用前注意
TKE集群版本 >= 1.16,详见 cbs csi 文档 仅 cbs csi 插件支持扩容,确保 csi 插件为最新版本 可以在扩容前使用快照来备份数据,避免扩容失败导致数据丢失。参见下方 3.2.1 使用快照备份云硬盘
2.2 如何使用
2.2.1 创建允许扩容的 StorageClass
在 storageclass 中设置allowVolumeExpansion为true:
allowVolumeExpansion: true apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: cbs-csi-expand parameters: diskType: CLOUD_PREMIUM provisioner: com.tencent.cloud.csi.cbs reclaimPolicy: Delete volumeBindingMode: Immediate
2.2.2 不重启 pod 的情况下在线扩容
1、确认扩容前 pv 和文件系统状态,大小均为 20G
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdd 20511312 45036 20449892 1% /usr/share/nginx/html $ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 20Gi RWO Delete Bound default/ cbs-csi 20h
2、执行以下命令修改 PVC 对象中的容量,扩容至 30G
$ kubectl patch pvc -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}'
执行后稍等片刻,可以发现 pv 和文件系统已经扩容至 30G:
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdd 30832548 44992 30771172 1% /usr/share/nginx/html $ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 30Gi RWO Delete Bound default/ cbs-csi 20h
2.2.3 重启 pod 的情况下在线扩容
1、确认扩容前 pv 和文件系统状态,大小均为 30G
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdd 30832548 44992 30771172 1% /usr/share/nginx/html $ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 30Gi RWO Delete Bound default/ cbs-csi 20h
2、使用下面命令给 PV 对象打标签,打一个非法 zone,旨在下一步重启 pod 后 pod 无法调度到某个节点上
$ kubectl label pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c failure-domain.beta.kubernetes.io/zone=nozone
3、重启 pod。重启后由于 pod 对应的 pv 的标签表明的是非法 zone,pod 会处于 Pending 状态
$ kubectl delete pod ivantestweb-0 $ kubectl get pod ivantestweb-0 NAME READY STATUS RESTARTS AGE ivantestweb-0 0/1 Pending 0 25s $ kubectl describe pod ivantestweb-0 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 40s (x3 over 2m3s) default-scheduler 0/1 nodes are available: 1 node(s) had no available volume zone.
4、修改 PVC 对象中的容量,扩容至 40G
kubectl patch pvc -p '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'
5、去掉 PV 对象之前打的标签,这样 pod 就能调度成功了。
$ kubectl label pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c failure-domain.beta.kubernetes.io/zone-persistentvolume/pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c labeled
稍等片刻,pod running,对应的 pv 和文件系统也扩容成功,从 30G 扩容到 40G 了
$ kubectl get pod ivantestweb-0 NAME READY STATUS RESTARTS AGE ivantestweb-0 1/1 Running 0 17m $ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 40Gi RWO Delete Bound default/ cbs-csi 20h $ kubectl get pvc www1-ivantestweb-0 NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE Bound pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 40Gi RWO cbs-csi 20h $ kubectl exec ivantestweb-0 df /usr/share/nginx/html Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdd 41153760 49032 41088344 1% /usr/share/nginx/html
3、如何创建快照和使用快照来恢复卷?
3.1 使用前注意
TKE集群版本 >= 1.18,详见 cbs csi 文档 仅 cbs csi 插件支持快照,确保 csi 插件镜像为最新版本
3.2 如何使用
3.2.1 使用快照备份云硬盘
1、使用下面 yaml,创建VolumeSnapshotClass对象
apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshotClass metadata: name: cbs-snapclass driver: com.tencent.cloud.csi.cbs deletionPolicy: Delete
创建后显示:
$ kubectl get volumesnapshotclass NAME DRIVER DELETIONPOLICY AGE cbs-snapclass com.tencent.cloud.csi.cbs Delete 17m
2、使用下面 yaml,创建
apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshot metadata: name: new-snapshot-demo spec: volumeSnapshotClassName: cbs-snapclass source: persistentVolumeClaimName: csi-pvc
创建后稍等片刻,volumesnapshot 和 volumesnapshotcontent 对象都创建成功,READYTOUSE为 true:
$ kubectl get volumesnapshot NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE new-snapshot-demo true 10Gi cbs-snapclass snapcontent-ea11a797-d438-4410-ae21-41d9147fe610 22m 22m $ kubectl get volumesnapshotcontent NAME READYTOUSE RESTORESIZE DELETIONPOLICY DRIVER VOLUMESNAPSHOTCLASS VOLUMESNAPSHOT AGE snapcontent-ea11a797-d438-4410-ae21-41d9147fe610 true 10737418240 Delete com.tencent.cloud.csi.cbs cbs-snapclass new-snapshot-demo 22m
具体快照 id 在 volumesnapshotcontent 对象中,status.snapshotHandle(snap-e406fc9m),可以根据这个快照 id 在腾讯云控制台确认快照是否存在
$ kubectl get volumesnapshotcontent snapcontent-ea11a797-d438-4410-ae21-41d9147fe610 -oyaml apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshotContent metadata: creationTimestamp: "2020-11-04T08:58:39Z" finalizers: - snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection name: snapcontent-ea11a797-d438-4410-ae21-41d9147fe610 resourceVersion: "471437790" selfLink: /apis/snapshot.storage.k8s.io/v1beta1/volumesnapshotcontents/snapcontent-ea11a797-d438-4410-ae21-41d9147fe610 uid: 70d0390b-79b8-4276-aa79-a32e3bdef3d6 spec: deletionPolicy: Delete driver: com.tencent.cloud.csi.cbs source: volumeHandle: disk-7z32tin5 volumeSnapshotClassName: cbs-snapclass volumeSnapshotRef: apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshot name: new-snapshot-demo namespace: default resourceVersion: "471418661" uid: ea11a797-d438-4410-ae21-41d9147fe610 status: creationTime: 1604480319000000000 readyToUse: true restoreSize: 10737418240 snapshotHandle: snap-e406fc9m
3.2.2 从快照恢复卷(云硬盘)
1、我们在 3.2.1 中创建的VolumeSnapshot的对象名为new-snapshot-demo,使用下面 yaml 来从快照恢复一个卷
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: restore-test spec: storageClassName: cbs-csi dataSource: name: new-snapshot-demo kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
发现 restore 的 pvc 已经创建出来,diskid 也在 pv 中(disk-gahz1kw1)
$ kubectl get pvc restore-test NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE restore-test Bound pvc-80b98084-29a3-4a38-a96c-2f284042cf4f 10Gi RWO cbs-csi 97s $ kubectl get pv pvc-80b98084-29a3-4a38-a96c-2f284042cf4f -oyaml apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: com.tencent.cloud.csi.cbs creationTimestamp: "2020-11-04T12:08:25Z" finalizers: - kubernetes.io/pv-protection name: pvc-80b98084-29a3-4a38-a96c-2f284042cf4f resourceVersion: "474676883" selfLink: /api/v1/persistentvolumes/pvc-80b98084-29a3-4a38-a96c-2f284042cf4f uid: 5321df93-5f21-4895-bafc-71538d50293a spec: accessModes: - ReadWriteOnce capacity: storage: 10Gi claimRef: apiVersion: v1 kind: PersistentVolumeClaim name: restore-test namespace: default resourceVersion: "474675088" uid: 80b98084-29a3-4a38-a96c-2f284042cf4f csi: driver: com.tencent.cloud.csi.cbs fsType: ext4 volumeAttributes: diskType: CLOUD_PREMIUM storage.kubernetes.io/csiProvisionerIdentity: 1604478835151-8081-com.tencent.cloud.csi.cbs volumeHandle: disk-gahz1kw1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: topology.com.tencent.cloud.csi.cbs/zone operator: In values: - ap-beijing-2 persistentVolumeReclaimPolicy: Delete storageClassName: cbs-csi volumeMode: Filesystem status: phase: Bound
参考
Kubernetes CSI in Action: Explained with Features and Use Cases CSI Volume Plugins in Kubernetes Design Doc
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~