k8s学习之路【03.容器持久化存储】

K8s持久化存储 Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。要使用 Volume,Pod 必须事先知道如下信息:Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息:要么询问管理员。 要么自己就是管理员。这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。Kubernetes 给出的解 阅读详情

容器持久化存储

容器的本质是进程,对于进程,Linux系统有进程组的概念来将其组织在一起。在k8s里面,使用Pod这个逻辑概念来维护容器间的关系。

图来自极客时间

有了Pod后,我们的应用程序需要被创建和管理,这就引出了ReplicaSet和Deployment;然后需要将部署好的应用暴露给外部进行访问,Service可以提供一个固定的 ip 和端口让外部访问。

对于有状态的应用,可以使用StatefulSet来进行状态的恢复,在上一节概念介绍[1]里面有提到,有状态的应用是离不开持久化存储的。

引子

在Docker中,如果一个容器在运行过程中会产生数据并写入到文件系统,当关闭这个容器,用镜像再启动一个容器的时候,你就会意识到新容器并不会识别前一个容器写入文件系统内的任何内容。

对于有状态的应用,我们希望下次启动的应用可以保持住上次的状态;在k8s里面可以通过定义存储卷来满足这个需求,它们不像Pod这样的顶级资源,而是被定义为Pod的一部分,并和Pod共享相同的生命周期。因此在Pod里面容器重新启动期间,卷的内容是不变的,

卷

emptyDir

在Pod中如何定义卷?让我们从emptyDir开始。设想一个这样的例子,一个Pod应用由两个容器,容器 A 不断产生数据,容器 B 将 A 产生的数据作为输出。此时,这两个容器就需要使用同一个卷。

让我们实际操作一下,vim fortune-pod.yaml:


apiVersion: v1
kind: Pod
metadata:
  name: fortune
spec:
  containers:
  - image: luksa/fortune
    name: html-generator
    volumeMounts:
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alpine
    name: web-server
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
  volumes:
  - name: html
    emptyDir: {}

说明一下上述配置文件的含义:fortune镜像是k8s in action书中示例打包的镜像,相当于上面说的不断产生数据的容器 A,其中名为html的容器挂载在var/htdocs中;而nginx也挂载了相同的html卷,不过位置在/usr/share/nginx/html,上面两个容器共用的卷就是emptyDir: {}。

启动来感受一下:

kubectl create -f fortune-pod.yaml
# 输出
pod/fortune created

# 查看状态
kubectl get pods
# 输出
NAME      READY   STATUS    RESTARTS   AGE
fortune   2/2     Running   0          2m27s

# 暂时服务化
kubectl port-forward fortune 8080:80

此时服务就处于可用状态了,在终端输入curl http://localhost:8080/,基本上每隔10s,都会返回不同的响应,如下图:

image-20210305144115418

emptyDir卷是最简单的卷类型,但是其他类型的卷都是在它的基础上构建的,在创建空目录后,相应的容器会将数据写入。

gitRepo

假设你有在github上开发项目,gitRepo卷允许你定义好相关配置然后直接从github上下拉项目将数据共享给其他容器使用。

hostPath

前面说的卷都是停留在共享同一个Pod的文件,当其需要读取节点文件的时候,就需要hostPath卷出场了。和之前介绍的卷最大的不同之处是,hostPath是一个持久性存储的卷,其目录存在于对应节点主机的目录。

所以,hostPath仅仅适用于在节点上读取数据,如果你的需求是跨Pod,那么NAS才是你的解决方案。

NFS

目前相关的云商都会有一套自己的持久化方式,我目前是自己搭建的k8s,所以我只能实践一下NAS方案,新建文件vim mongodb-pod-nfs.yaml,输入以下内容:

apiVersion: v1
kind: Pod
metadata:
  name: mongodb-nfs
spec:
  volumes:
  - name: mongodb-data
    nfs:
      server: 1.2.3.4
      path: /some/path
  containers:
  - image: mongo
    name: mongodb
    volumeMounts:
    - name: mongodb-data
      mountPath: /data/db
    ports:
    - containerPort: 27017
      protocol: TCP

启动:

kubectl create -f mongodb-pod-nfs.yaml

# 查看状态
kubectl get pods
# 输出
NAME          READY   STATUS    RESTARTS   AGE
mongodb-nfs   1/1     Running   0          3m13s

我们来验证一下数据持久化是否生效,输入命令kubectl exec -it mongodb-nfs mongo进入:

> use test_data
switched to db test_data

# 插入
> db.test.insert({"name": "howie"})
WriteResult({ "nInserted" : 1 })

# 查询
> db.test.find({})
{ "_id" : ObjectId("6041f5bc0c893dc3bb362e75"), "name" : "howie" }

接下来重新创建Pod看一下数据是不是还在:

kubectl delete pod mongodb-nfs

# 重新创建
kubectl create -f mongodb-pod-nfs.yaml
# 输出
pod/mongodb-nfs created

# 查看
kubectl get pods
# 输出
NAME          READY   STATUS    RESTARTS   AGE
mongodb-nfs   1/1     Running   0          28s

进入Pod内的mongo容器,输入命令kubectl exec -it mongodb-nfs mongo进入:

> use test_data
switched to db test_data

# 查询
> db.test.find({})
{ "_id" : ObjectId("6041f5bc0c893dc3bb362e75"), "name" : "howie" }

虽然我们成功让多个Pod享用了同一份数据,但这样做法有点问题,让开发人员在配置里面写具体NFS地址是很不友好的事情,我们可以使用持久卷来解决此问题。

持久卷&持久卷声明

介绍

前面NFS用来做持久化存储是一个反面的例子,对于真实的基础设施,其详细配置应该是被隐藏的;但是k8s又实实在在需要对一些基础设施进行访问,怎么办?引入新的资源:

  • 持久卷(PersistentVolume)

  • 持久卷声明(PersistentVolumeClaim)

持久卷由管理员创建(各种配置信息),然后用户创建持久卷声明,提交后k8s就会找到匹配的持久卷并将其绑定到持久卷声明。

image-20210305175203591

这样做的好处在于,对于用户只需要关注声明一下需要多大的存储、需要什么权限(读写)等,然后 pod 通过其中一个卷的名称来引用声明就可以了,将细节完美地进行了隐藏。

实践

首先建立一个NFS类型的PV(一般是管理员进行创建),在终端输入vim mongodb-pv-nfs.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 10Mi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 1.2.3.4
    path: "/"

接下来创建持久卷:

kubectl create -f mongodb-pv-nfs.yaml
# 输出
persistentvolume/nfs created

# 查看
kubectl get pv
# 输出
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   10Mi       RWX            Retain           Available                                   6s

# 关于删除
# kubectl delete pv nfs-pv

可以看到状态已经生效。

接下来就轮到使用者随意使用PV了,如果作为使用者,部署的Pod需要持久化存储,那么其需要做的就是创建PVC,在终端输入vim mongodb-pvc-nfs.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi
  storageClassName: ""

然后创建持久化声明:

kubectl create -f mongodb-pvc-nfs.yaml
# 输出
persistentvolumeclaim/nfs created

# 查看 pvc
kubectl get pvc
# 输出,注意状态是绑定
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   10Mi       RWX                           6s

# 查看 pv
kubectl get pv
# 输出,状态是绑定
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   10Mi       RWX            Retain           Bound    default/nfs-pvc                           3m6s
# 关于删除
# kubectl delete pvc nfs-pvc

对于ACCESS MODES,主要分为以下几种:

  • RWO:ReadWriteOnce(仅允许单个节点挂载读写)

  • ROX:ReadOnlyMany(允许多个节点挂载只读)

  • RWX:ReadWriteMany(允许多个节点挂载读写这个卷)

现在,准备工作就绪,在Pod中使用持久卷就是引用持久卷名称,在终端输入vim mongo-pod-pvc.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  containers:
  - image: mongo
    name: mongodb
    volumeMounts:
    - name: mongodb-data
      mountPath: /data/db
    ports:
    - containerPort: 27017
      protocol: TCP
  volumes:
  - name: mongodb-data
    persistentVolumeClaim:
      claimName: nfs-pvc

创建Pod:

# 先删除原先创建的 mongo Pod
kubectl delete pod mongodb-nfs
# 创建引用持久卷声明的 Pod
kubectl create -f mongodb-pod-pvc.yaml
# 输出
pod/mongodb created

进入Pod内的mongo容器,输入命令kubectl exec -it mongodb mongo进入:

> use test_data
switched to db test_data

# 查询
> db.test.find({})
{ "_id" : ObjectId("6041f5bc0c893dc3bb362e75"), "name" : "howie" }

没问题,引用了之前的NFS下的对应目录。

动态卷

前面提到,PV需要管理人员进行创建,在实际生产环境下,这个PV的需求量可能是非常大的,所以这种协调方式是不合理的。所以,k8s提供了一套可以自动创建PV的机制——动态卷。

image-20210305213129142

这张图将使用StorageClass的流程描述地很清楚,管理员创建一个或多个StorageClass,用户创建Pod引用PVC声明相关的storageClassName就会通过管理员创建的StorageClass自动创建PV。

参考

本章关于容器持久化就介绍到这里了,谢谢!本部分内容有参考如下文章:

  • 深入剖析 Kubernetes[2]:持久化存储部分

  • Kubernetes in Action[3]中文版:可以算是第 6 章的读书笔记

参考资料

[1]

概念介绍: https://www.howie6879.cn/p/k8s%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF.02.%E6%A6%82%E5%BF%B5%E4%BB%8B%E7%BB%8D/

[2]

深入剖析Kubernetes: https://time.geekbang.org/column/intro/100015201?code=UhApqgxa4VLIA591OKMTemuH1%2FWyLNNiHZ2CRYYdZzY%3D

[3]

Kubernetes in Action: https://github.com/luksa/kubernetes-in-action

系列笔记:

如果对你有帮助,欢迎转发分享,点个好看呗哈哈 ????

运维必会——K8s容器编排引擎 Kubernetes作为一款。 阅读详情

相关推荐

Kubernetes的五大开源存储项目

在Kubernetes中,关于数据的持久化管理是一种挑战,对此,社区提供了多种存储的解决方案,这些方案旨在简化和优化容器化应用程序的持久化数据管理。本文将介绍 Kubernetes 的五大开源存储项目,带你了解开源存储解决方案的多种优势。01。

风水道人 610

docker--容器数据进行持久化存储的三种方式

Docker是一种流行的容器化技术,它允许开发者将应用程序及其依赖打包在一个轻量级、可移植的容器中。与虚拟机不同,Docker容器共享主机操作系统的内核,因此更轻便和高效。持久化存储指的是保存数据的方法,这些数据在应用程序或系统重启后仍然存在。在传统计算中,我们通常将数据存储在硬盘、数据库或外部存储设备上。Docker 卷是由 Docker 管理的存储,可以独立于容器生命周期存在,适合需要在多个容器之间共享或持久化数据的场景。

lwxvgdv的博客 7240

kubernetes(k8s)之概念入门篇

kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,kubernetes的目标是然该部署容器化的应用简单而且高效,kubernetes提供了应用部署,规划,更新,维护的一种机制。其实提到管理容器第一想到的肯定是docker compose,只不过他是单主机的;而k8s是天然的用于多主机管理的应用,显然功能更加强大。kubernetes这个名字源于希腊语,以为“舵手”、“飞行员”。“K8S”这个缩写是因为k和s之间有八个字符,所以这样缩写。

mijichui2153的博客 1384

容器数据持久化

一、挂载方式 Docker提供三种方式将数据从宿主机挂载到容器中: volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。 bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。 tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用tmpfs,同时避免写入容器可写层提高性能。 二、Volume #管理卷: docker volume ls docker

贾文超的博客 782

kubernetes k8s+DevOps云原生全栈技术实战课程

第16章 Pod进阶篇:污点-容忍度-亲和性-Affinity-调度。第21量 K8s应用篇-Service代理和kube-proxy转发。第22章 K8s应用篇-持久化存储和StorageClass详细介绍。第34章 实战-在k8s集群中部署SpringCloud在线购物平台。第37章 扩展篇:HPA-KPA-VPA-CA实现k8s自动扩缩容。第11章 kubeadm安装高可用的k8s集群-适合生产环境。第25章 K8s应用篇-配置管理中心Configmap。

niwoxiangyu的博客 852

西门子V90 PN伺服控制核心:FB284功能块详解与实战

在工业自动化中,伺服定位控制是运动控制的基础环节,其本质是PLC通过PROFINET协议与伺服驱动器实现高速、确定性数据交互。FB284作为西门子为V90 PN定制的标准化功能块,封装了GSD映射、状态机管理与周期性PDO同步机制,将底层寄存器操作抽象为高可靠调用接口。相比MOVE指令或MC_MoveAbsolute等通用方案,FB284显著降低时序错乱风险,提升多轴同步精度与故障响应能力。它广泛应用于包装、灌装、装配等中端产线,尤其适配S7-1200/1500平台下的快速部署与现场维护。本文聚焦V90 P

weixin_42696271的博客 300

【Docker】容器持久化存储全攻略

在容器化应用中,容器的轻量级、可移植性、易扩展等特性使其成为现代应用开发和部署的首选。但容器的短暂性和易丢失数据的问题也随之而来。默认情况下,容器在销毁后,容器内部的数据会随之消失,因此,如何实现数据的持久化存储变得尤为关键。本文将深入探讨容器的数据持久化存储机制,并介绍几种常用的实现方式。容器化的应用发展迅速,而数据持久化存储作为其中的关键问题之一,也有了多种解决方案。

qq_32589989的博客 1283

Landsat9 地表温度反演方法

landsat9地表温度反演及缺失值处理方法

xiangliu12345的博客 3919

Docker容器数据持久化存储机制

物理机或虚拟机数据持久化存储由于物理机或虚拟机本身就拥有大容量的磁盘,所以可以直接把数据存储在物理机或虚拟机本地文件系统中,亦或者也可以通过使用额外的存储系统(NFS、GlusterFS、Ceph等)来完成数据持久化存储。Docker容器数据持久化存储由于Docker容器是由容器镜像生成的,所以一般容器镜像中包含什么文件或目录,在容器启动后,我们依旧可以看到相同的文件或目录。由于Docker容器属于"用后即焚”型计算资源,因此Docker容器不适合做数据持久化存储。

python全栈 1521

用RFSoC ZU47DR搭建软件无线电原型:从零配置Vivado到生成第一个射频信号

本文详细介绍了如何使用Xilinx RFSoC ZU47DR开发板搭建软件无线电原型系统,从Vivado环境配置到生成首个射频信号的全流程。通过整合ARM处理器、FPGA逻辑和高速ADC/DAC,该平台为通信算法验证提供了高效解决方案,特别适合SDR开发者和通信工程师快速实现原型设计。

weixin_26763955的博客 592

语言随机效应模型_线性混合效应模型 VS 方差分析

线性混合效应模型相比方差分析具有很多优点。为了让大家更直观的了解,我们来做一下两者的对比。基于模拟的方法,生成了以下数据dat_sim:这种数据格式是长格式,也就是从实验软件导出来的那种数据格式。这种数据格式可以直接使用线性混合效应模型进行分析。该实验设计是被试内项目间的单因素两水平设计。category是自变量,两个水平分别是outgroup和ingroup,outgroup比ingr...

weixin_31960565的博客 2688

探索 Kubernetes 持久化存储之 Longhorn 初窥门径

作者:运维有术星主在 Kubernetes 生态系统中,持久化存储扮演着至关重要的角色,它是支撑业务应用稳定运行的基石。对于那些选择自建 Kubernetes 集群的运维架构师而言,选择合适的后端持久化存储解决方案是一项至关重要的选型决策。目前 Ceph、GlusterFS、NFS、openEBS 等解决方案已被广泛采用。往期文章,我分享过最简单、实用的。为了丰富我们的技术栈,并为未来的容器云平台设计持久化存储提供更多灵活性和选择性。

KubeSphere 1784

拆解一个800G光模块:手把手带你认识里面的MT插芯和光纤阵列(FA)

本文详细拆解了800G光模块中的关键组件MT插芯和光纤阵列(FA),揭示了并行光学技术如何实现高速数据传输。通过显微镜下的精密观察,展示了MT插芯的高精度构造和光纤阵列的连接奥秘,同时解析了高精度研磨工艺对光信号传输的重要性。这些微型组件是高速收发模块实现800Gbps带宽的核心技术。

weixin_30839881的博客 1557

探索 Kubernetes 持久化存储之 Rook Ceph 初窥门径

在 Kubernetes 生态系统中,持久化存储是支撑业务应用稳定运行的基石,对于维护整个系统的健壮性至关重要。对于选择自主搭建 Kubernetes 集群的运维架构师来说,挑选合适的后端持久化存储解决方案是关键的选型决策。目前,Ceph、GlusterFS、NFS、Longhorn 和 openEBS 等解决方案已在业界...

qq_35485206的博客 1294

引文:当SVM转角遇上Copy-on-Write (COW)

本文分析了Linux内核中fork系统调用的Copy-on-Write(COW)机制实现原理。重点阐述了fork时父子进程共享物理页面、标记页表项为只读并在写操作时触发COW的流程,以及在SVM环境中通过MMU Notifier机制保持CPU和GPU页表同步的解决方案。文章详细描述了COW的三个阶段:初始共享、写入触发和页面复制,并说明了MMU Notifier的回调注册和处理流程,确保异构计算环境下内存一致性。

图形/计算GPU的驱动与虚拟化技术分享园地 2675

18年陕西省TI杯电赛无人机赛题视觉部分

更新: 相同任务另外两种不同的视觉方法: https://blog.csdn.net/qq_41895747/article/details/97613077 https://blog.csdn.net/qq_41895747/article/details/97614971 任务:识别前方的方框,无人机从方框中飞出去 视觉任务:识别特定方框,返回方框中心坐标 # -*- codin...

沉迷单车的追风少年 1506

Kubernetes(K8s)详解

Kubernetes(K8S)是一个开源的容器编排引擎,用于自动化部署、扩缩和管理容器化应用。其核心架构包括Master Node(含API Server、Scheduler、Controller Manager等组件)和Worker Node(含Kubelet、Kube-Proxy等)。K8S提供核心特性如服务发现、存储编排、自我修复等,支持通过kubectl命令行工具进行资源管理。Namespace用于隔离资源,Pod是最小部署单元,而Deployment则管理Pod的多副本和自愈能力。通过YAML文件

Java资料站 2013

YOLO11涨点优化:小目标检测 | 多头检测器提升小目标检测精度

引入多头检测器助力YOLO11,添加一个微小物体的检测头暴力提升小目标检测性能

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 4742

【K8S】K8S架构及相关组件

K8S,全称Kubernetes,是一个开源的容器部署和管理平台,由Google开发,后捐献给云原生计算基金会(CNCF)。K8S提供了容器编排、容器运行时、以容器为中心的基础设施编排、负载平衡、自我修复机制和服务发现等功能。K8S的架构采用主从设备模型(Master-Slave架构),即由Master节点负责集群的调度、管理和运维,Slave节点作为集群中的运算工作负载节点。

黄小黄的博客 4918

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

k8s中使用MySQL共享存储_k8s存储方式的介绍及应用 (持久化,mysql对数据持久化...

k8s存储方式的介绍及应用 (持久化,mysql对数据持久化发布时间:2020-03-02 07:42:52来源:51CTO阅读:672作者:mb5cd21e691f31a栏目:云计算k8s存储: (持久化)docker容器是有生命周期的。volume1,存储类(Storage class)是k8s资源类型的一种,它是有管理员为管理PV更加方便创建的一个逻辑组,可以按照存储系统的性能高低,或者综合...

weixin_39967938的博客 443

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【K8S】为什么需要Kubernetes?

Kubernetes是 一个开源的,用于管理云平台中多个主机上的容器化应用,Kubernetes提供了应用部署,规划,更新,维护的一种机制,其目标是为了让部署容器化的应用简单、高效~那么,为啥需要Kubern这还需要从应用的部署方式说起~

黄小黄的博客 2082

容器持久化存储训练营”启动倒计时!3天攻破K8s难点

根据 CNCF 最新调查结果,企业在生产环境中使用 Kubernetes 的比例从 78% 提高到了 83%,Kubernetes 作为云原生的核心平台,吸引了越来越多的开发者去了解、学习和掌握。 在此基础之上,伴随着云原生对业务创新的影响力持续显现,企业将容器应用于生产环境成为大势所趋,数据持久化存储问题一直以来都是容器技术的一大挑战。 为了解决上述问题,快速帮助开发者攻克 Kubernetes 技术难题,我们和 ACK CNFS 及 NAS 的开发团队一起准备了一场“硬核”训练营,为大家带来干货满满的直

阿里巴巴云原生的博客 236

部署kubernetes集群和POD持久化存储storageclass

前面的例子中,我们提前创建了 PV,然后通过 PVC 申请 PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。与之对应的是动态供给(Dynamical Provision),即如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高。

xq477681339的博客 966

03-k8s的pod资源01-数据持久化、env环境变量、网络暴露

1,容器挂掉,数据不会丢失;2,pod挂掉,数据会丢失;3,所以,不推荐使用;

2302_79199605的博客 2468

Kubernetes 持久化存储之 Rook Ceph 探究

修改配置文件rook-ceph 所有管理组件部署在指定标签节点k8s 其他节点安装 Ceph CSI Plugin本文使用比较稳定、可靠的 Block Storage(RBD)的方式作为 Kubernetes 的持久化存储。

qyq88888的专栏 325
上一篇: 一站式机器学习云研发平台
下一篇: 设计模式——基于容器的分布式系统
老胡的储物柜
博客等级 码龄12年 1145粉丝 284原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值