Kubernetes存储管理与Volume系统:持久化数据解决方案

Kubernetes存储管理与Volume系统:持久化数据解决方案

本文深入探讨了Kubernetes存储系统的核心组件和机制,包括Volume类型体系架构、生命周期管理流程、PersistentVolume与PersistentVolumeClaim的核心抽象、StorageClass动态存储配置以及CSI容器存储接口标准。文章详细分析了Kubernetes如何通过插件化架构为云原生应用提供可靠的数据持久化解决方案,涵盖了从基础概念到高级特性的完整知识体系。

Volume类型与生命周期管理

Kubernetes存储系统的核心在于Volume类型及其完整的生命周期管理机制。Volume不仅是简单的数据存储单元,更是连接容器与持久化存储的桥梁,为云原生应用提供了可靠的数据持久化解决方案。

Volume类型体系架构

Kubernetes Volume系统采用插件化架构,支持多种存储后端类型,每种类型都有其特定的使用场景和生命周期管理策略。

核心Volume接口定义

Kubernetes通过定义清晰的接口规范来实现Volume的统一管理:

// Volume基础接口
type Volume interface {
    GetPath() string
    MetricsProvider
}

// 块设备Volume接口
type BlockVolume interface {
    GetGlobalMapPath(spec *Spec) (string, error)
    GetPodDeviceMapPath() (string, string)
    SupportsMetrics() bool
    MetricsProvider
}

// 挂载器接口
type Mounter interface {
    Volume
    SetUp(mounterArgs MounterArgs) error
    SetUpAt(dir string, mounterArgs MounterArgs) error
    GetAttributes() Attributes
}

// 卸载器接口
type Unmounter interface {
    Volume
    TearDown() error
    TearDownAt(dir string) error
}
Volume插件类型分类

Kubernetes支持丰富的Volume插件类型,主要分为以下几类:

Volume类型存储特性适用场景生命周期
EmptyDir临时存储容器间共享临时数据Pod生命周期
HostPath节点本地存储开发测试环境节点重启后数据保留
NFS网络文件系统共享文件存储持久化存储
iSCSI块存储高性能数据库持久化存储
AWS EBS云块存储云环境持久化持久化存储
ConfigMap配置数据应用配置管理配置更新时同步
Secret敏感数据密钥证书管理安全存储

Volume生命周期管理流程

Volume的生命周期管理遵循严格的状态转换机制,确保数据的一致性和可靠性。

Volume挂载流程

mermaid

详细挂载过程
  1. Volume插件发现与初始化

    func ProbeVolumePlugins() []volume.VolumePlugin {
        return []volume.VolumePlugin{&nfsPlugin{}}
    }
    
  2. Attach阶段(块设备)

    func (a *nfsAttacher) Attach(spec *Spec, nodeName types.NodeName) (string, error) {
        // 执行网络存储挂载逻辑
        return devicePath, nil
    }
    
  3. Mount阶段

    func (mounter *nfsMounter) SetUp(mounterArgs MounterArgs) error {
        // 创建挂载目录
        // 执行mount命令
        // 设置文件权限
        return nil
    }
    

Volume状态管理与监控

Kubernetes提供完善的Volume状态监控机制,确保存储系统的健康运行。

Volume Metrics监控
type Metrics struct {
    Time        metav1.Time
    Used        *resource.Quantity
    Capacity    *resource.Quantity
    Available   *resource.Quantity
    InodesUsed  *resource.Quantity
    Inodes      *resource.Quantity
    InodesFree  *resource.Quantity
    Abnormal    *bool
    Message     *string
}
Volume健康状态检查

mermaid

Volume资源清理与回收

Volume卸载和清理是生命周期管理的重要环节,确保资源正确释放。

清理流程示例
func (unmounter *nfsUnmounter) TearDown() error {
    // 1. 卸载文件系统
    if err := unmountPath(mountPath); err != nil {
        return err
    }
    
    // 2. 清理临时文件
    if err := os.RemoveAll(mountPath); err != nil {
        return err
    }
    
    // 3. 释放网络连接
    return releaseNFSConnection(volumeID)
}
Volume回收策略

Kubernetes支持多种Volume回收策略:

回收策略描述适用场景
Retain保留数据重要数据备份
Delete删除存储临时测试数据
Recycle清理重用开发环境

高级Volume特性

Volume扩容机制
func (expander *volumeExpander) ExpandVolume() error {
    // 检查存储系统支持情况
    if !expander.plugin.CanExpand() {
        return errors.New("volume expansion not supported")
    }
    
    // 执行扩容操作
    newSize, err := expander.plugin.Expand(expander.spec, expander.newSize)
    if err != nil {
        return err
    }
    
    // 更新文件系统
    return expander.resizeFilesystem(newSize)
}
Volume快照管理

mermaid

最佳实践与性能优化

Volume配置优化
apiVersion: v1
kind: PersistentVolume
metadata:
  name: optimized-volume
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: fast-ssd
  mountOptions:
    - noatime
    - nodiratime
    - data=ordered
性能监控指标
// Volume性能监控指标
type VolumePerformanceMetrics struct {
    IOPSRead         int64
    IOPSWrite        int64
    ThroughputRead   int64  // KB/s
    ThroughputWrite  int64  // KB/s
    LatencyRead      time.Duration
    LatencyWrite     time.Duration
    QueueDepth       int32
    Utilization      float64 // 百分比
}

通过完善的Volume类型体系和生命周期管理机制,Kubernetes为云原生应用提供了强大而灵活的存储解决方案,确保数据持久化、高可用性和性能优化的完美平衡。

PersistentVolume与PersistentVolumeClaim:Kubernetes存储管理的核心抽象

在Kubernetes的存储生态系统中,PersistentVolume(PV)和PersistentVolumeClaim(PVC)构成了存储资源管理的核心抽象层。这两个资源对象通过声明式API实现了存储资源的动态分配和管理,为有状态应用提供了可靠的持久化存储解决方案。

PV与PVC的基本概念

PersistentVolume(PV) 是集群中的一块网络存储资源,由集群管理员预先配置或通过StorageClass动态 provision。PV是集群级别的资源,独立于Pod的生命周期,可以被多个Pod跨命名空间共享使用。

PersistentVolumeClaim(PVC) 是用户对存储资源的请求,类似于Pod消耗节点资源的方式。PVC是命名空间级别的资源,用户通过创建PVC来声明所需的存储特性,Kubernetes会自动为其绑定合适的PV。

PV与PVC的详细规范

PersistentVolume规范详解

PV的规范定义了存储卷的完整配置,包括容量、访问模式、存储类型等关键属性:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: fast
  volumeMode: Filesystem
  nfs:
    path: /exports/data
    server: nfs-server.example.com
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.kubernetes.io/zone
          operator: In
          values:
          - us-west-2a

关键字段说明:

  • capacity: 定义存储容量,支持Gi、Mi等单位
  • accessModes: 访问模式,包括:
    • ReadWriteOnce: 可被单个节点读写挂载
    • ReadOnlyMany: 可被多个节点只读挂载
    • ReadWriteMany: 可被多个节点读写挂载
  • persistentVolumeReclaimPolicy: 回收策略:
    • Retain: 保留数据,手动清理
    • Recycle: 删除数据并重新可用
    • Delete: 删除存储资源
  • volumeMode: 卷模式,Filesystem(文件系统)或Block(块设备)
PersistentVolumeClaim规范详解

PVC规范定义了用户对存储资源的需求:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: fast
  volumeMode: Filesystem
  selector:
    matchLabels:
      environment: production
  dataSource:
    kind: VolumeSnapshot
    name: db-backup-snapshot

关键字段说明:

  • resources.requests.storage: 请求的存储容量
  • storageClassName: 指定需要的存储类
  • selector: 标签选择器,用于筛选特定PV
  • dataSource: 数据源,支持从快照或现有PVC克隆

PV与PVC的绑定机制

Kubernetes通过PV控制器实现PV与PVC的自动绑定,绑定过程遵循严格的匹配规则:

mermaid

绑定匹配条件包括:

  1. 存储容量匹配: PVC请求容量 ≤ PV可用容量
  2. 访问模式匹配: PVC访问模式 ⊆ PV支持的访问模式
  3. 存储类匹配: PVC指定的StorageClass与PV一致
  4. 标签选择器匹配: PVC的selector与PV标签匹配
  5. 卷模式匹配: PVC的volumeMode与PV一致

动态配置与静态配置

静态配置

管理员手动创建PV,PVC通过匹配条件绑定到现有PV:

# 静态PV示例
apiVersion: v1
kind: PersistentVolume
metadata:
  name: static-pv
  labels:
    type: local
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
动态配置

通过StorageClass自动创建PV,无需管理员干预:

# StorageClass定义
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"

生命周期管理

PV和PVC的生命周期包含多个状态转换:

mermaid

回收策略详解
  1. Retain(保留):

    • PVC删除后,PV进入Released状态
    • 数据保留,需要管理员手动清理
    • 适用于重要数据保护场景
  2. Recycle(回收):

    • 自动删除PV中的数据
    • 重新标记为Available状态
    • 基本清理,不保证完全安全
  3. Delete(删除):

    • 删除后端存储资源
    • PV对象同时从Kubernetes中删除
    • 适用于云存储动态配置场景

高级特性与使用模式

存储卷扩容

支持在线扩容PVC容量:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: expandable-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi # 可从5Gi扩容到此值
  storageClassName: expandable-sc
数据源克隆

从快照或现有PVC创建新卷:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cloned-pvc
spec:
  dataSource:
    kind: PersistentVolumeClaim
    name: source-pvc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
节点亲和性

限制PV可被调度的节点范围:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv
spec:
  capacity:
    storage: 100Gi
  local:
    path: /mnt/ssd
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node-1

最佳实践与注意事项

  1. 容量规划: 合理设置PV容量,避免资源浪费
  2. 访问模式选择: 根据应用需求选择合适的访问模式
  3. 回收策略: 根据数据重要性选择适当的回收策略
  4. 存储类设计: 定义清晰的StorageClass层次结构
  5. 监控告警: 监控PV/PVC状态和容量使用情况
  6. 备份策略: 重要数据配置定期快照和备份

故障排查与调试

常见问题及解决方法:

问题现象可能原因解决方案
PVC一直Pending无匹配PV/StorageClass配置错误检查StorageClass、检查PV资源
绑定失败容量/访问模式不匹配调整PVC需求或创建合适PV
挂载失败节点资源不足/网络问题检查节点状态、网络连通性
扩容失败存储后端不支持确认存储插件支持扩容功能

通过kubectl命令进行诊断:

# 查看PVC详情
kubectl describe pvc my-pvc

# 查看PV详情  
kubectl describe pv my-pv

# 查看存储类
kubectl get storageclass

# 查看事件信息
kubectl get events --sort-by='.lastTimestamp'

PV和PVC机制为Kubernetes提供了强大而灵活的存储管理能力,通过声明式API和自动化操作,大大简化了有状态应用的存储管理复杂度。正确理解和使用这些资源对象,是构建可靠分布式系统的关键基础。

StorageClass动态存储配置

在现代云原生应用中,存储管理是一个至关重要的环节。Kubernetes通过StorageClass机制提供了强大的动态存储配置能力,使得开发者无需手动创建和管理PersistentVolume,而是通过声明式的方式自动按需分配存储资源。

StorageClass核心概念

StorageClass是Kubernetes存储系统的核心组件,它定义了存储提供者(Provisioner)的类型以及创建存储卷时所需的参数。每个StorageClass都包含一个Provisioner,用于确定使用哪个卷插件来创建PersistentVolume。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

StorageClass关键字段详解

字段名称类型描述默认值
provisionerstring存储提供者类型,如aws-ebs、gce-pd等必填
parametersmap[string]string传递给Provisioner的参数{}
reclaimPolicyPersistentVolumeReclaimPolicy卷回收策略Delete
mountOptions[]string挂载选项[]
allowVolumeExpansion*bool是否允许卷扩展false
volumeBindingModeVolumeBindingMode卷绑定模式Immediate

动态存储配置流程

StorageClass的动态配置过程遵循一个清晰的流程:

mermaid

常用StorageClass配置示例

AWS EBS存储类配置
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: aws-gp3
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "4000"
  throughput: "250"
  encrypted: "true"
  kmsKeyId: alias/aws/ebs
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
Azure Disk存储类配置
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: azure-premium-ssd
provisioner: disk.csi.azure.com
parameters:
  skuname: Premium_LRS
  cachingMode: ReadOnly
  fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: Immediate
Google Cloud Persistent Disk配置
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gcp-ssd-regional
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-ssd
  replication-type: regional-pd
reclaimPolicy: Delete
allowVolumeExpansion: true

卷绑定模式详解

StorageClass支持两种卷绑定模式,这在调度和资源利用方面有重要影响:

Immediate模式(立即绑定)

mermaid

WaitForFirstConsumer模式(等待首次消费者)

mermaid

存储类的高级特性

卷扩展功能

allowVolumeExpansion设置为true时,支持在线扩展存储卷容量:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: expandable-storage
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
allowVolumeExpansion: true
拓扑感知配置

通过allowedTopologies字段可以限制存储卷的创建位置:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: topology-aware
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
allowedTopologies:
- matchLabelExpressions:
  - key: topology.ebs.csi.aws.com/zone
    values:
    - us-west-2a
    - us-west-2b

默认存储类配置

通过注解可以将StorageClass标记为默认存储类:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: default-storage
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
  type: gp2

最佳实践和建议

  1. 生产环境配置:为不同工作负载创建专用的StorageClass,如fast-ssd用于数据库,standard-hdd用于日志存储

  2. 成本优化:利用卷绑定模式WaitForFirstConsumer避免在不需要的可用区创建存储资源

  3. 安全考虑:为敏感数据启用加密功能,并在parameters中配置合适的加密密钥

  4. 监控和告警:监控存储类的使用情况,设置适当的配额和限制

  5. 备份策略:根据reclaimPolicy选择合适的回收策略,重要数据建议使用Retain策略

StorageClass的动态存储配置机制极大地简化了Kubernetes中的存储管理,通过声明式配置和自动化流程,为云原生应用提供了灵活、可靠的存储解决方案。

CSI容器存储接口标准

CSI(Container Storage Interface)是Kubernetes生态系统中的关键存储标准,它定义了一套容器编排系统与存储提供商之间的通用接口规范。CSI的设计目标是实现存储插件的标准化和去耦合,让存储提供商能够独立开发和维护他们的驱动程序,而无需修改Kubernetes核心代码。

CSI架构设计原理

CSI采用客户端-服务器架构,通过gRPC协议进行通信。整个架构包含三个核心组件:

1. CSI驱动组件 mermaid

2. 核心gRPC服务接口

  • Identity Service: 提供驱动身份识别和能力查询
  • Controller Service: 处理卷的生命周期管理(创建、删除、附加、分离)
  • Node Service: 在节点级别执行卷的挂载和卸载操作

Kubernetes中的CSI实现机制

Kubernetes通过pkg/volume/csi包实现了完整的CSI插件支持。核心组件包括:

CSI插件架构

// CSI插件核心结构
type csiPlugin struct {
    host                      volume.VolumeHost
    csiDriverLister           storagelisters.CSIDriverLister
    serviceAccountTokenGetter func(namespace, name string, tr *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error)
    volumeAttachmentLister    storagelisters.VolumeAttachmentLister
}

CSI客户端实现

// CSI客户端接口定义
type csiClient interface {
    NodeGetInfo(ctx context.Context) (nodeID string, maxVolumePerNode int64, accessibleTopology map[string]string, err error)
    NodePublishVolume(ctx context.Context, volumeid string, readOnly bool, stagingTargetPath string, targetPath string, accessMode api.PersistentVolumeAccessMode, publishContext map[string]string, volumeContext map[string]string, secrets map[string]string, fsType string, mountOptions []string, fsGroup *int64) error
    NodeUnpublishVolume(ctx context.Context, volID string, targetPath string) error
    // ... 其他方法
}

CSI API资源对象

Kubernetes为CSI定义了多个CRD(Custom Resource Definition)资源:

CSIDriver资源规范

apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
  name: example.csi.driver
spec:
  attachRequired: true
  podInfoOnMount: true
  volumeLifecycleModes:
  - Persistent
  - Ephemeral
  storageCapacity: true
  tokenRequests:
  - audience: storage.example.com
    expirationSeconds: 3600

CSINode资源示例

apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
  name: worker-node-1
spec:
  drivers:
  - name: example.csi.driver
    nodeID: "node-12345"
    allocatable:
      count: 10
    topologyKeys:
    - topology.example.com/zone

CSI操作流程详解

卷创建和挂载序列 mermaid

核心gRPC调用流程

// NodePublishVolume请求示例
req := &csipbv1.NodePublishVolumeRequest{
    VolumeId:       "volume-123",
    TargetPath:     "/var/lib/kubelet/pods/pod-uid/volumes/kubernetes.io~csi/volume-123/mount",
    Readonly:       false,
    PublishContext: map[string]string{"devicePath": "/dev/sdb"},
    VolumeContext:  map[string]string{"storage.kubernetes.io/csiProvisionerIdentity": "1234567890"},
    Secrets:        map[string]string{"username": "admin", "password": "secret"},
    VolumeCapability: &csipbv1.VolumeCapability{
        AccessMode: &csipbv1.VolumeCapability_AccessMode{
            Mode: csipbv1.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
        },
        AccessType: &csipbv1.VolumeCapability_Mount{
            Mount: &csipbv1.VolumeCapability_MountVolume{
                FsType:     "ext4",
                MountFlags: []string{"noatime"},
            },
        },
    },
}

高级特性支持

1. 拓扑感知调度 CSI支持拓扑约束,确保卷被调度到合适的节点:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: topology-aware
provisioner: example.csi.driver
parameters:
  type: ssd
allowedTopologies:
- matchLabelExpressions:
  - key: topology.kubernetes.io/zone
    values:
    - us-west-2a
    - us-west-2b

2. 存储容量追踪

apiVersion: storage.k8s.io/v1
kind: CSIStorageCapacity
metadata:
  name: capacity-example
  namespace: kube-system
storageClassName: example-sc
nodeTopology:
  matchLabels:
    topology.kubernetes.io/zone: us-west-2a
capacity: 1Ti
maximumVolumeSize: 100Gi

3. 临时卷支持 CSI支持临时卷,生命周期与Pod绑定:

apiVersion: v1
kind: Pod
metadata:
  name: csi-ephemeral-example
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: ephemeral-volume
      mountPath: /data
  volumes:
  - name: ephemeral-volume
    csi:
      driver: example.csi.driver
      volumeAttributes:
        size: "10Gi"
        type: "ssd"

安全与认证机制

CSI支持多种认证方式,包括Service Account Token投射:

Token请求配置

spec:
  tokenRequests:
  - audience: storage.example.com
    expirationSeconds: 3600
  - audience: metrics.example.com  
    expirationSeconds: 7200

卷上下文安全传递

// 安全的Secret传递
secrets := map[string]string{
    "username": "csi-service-account",
    "password": "generated-token-123456",
}

性能监控与指标

Kubernetes为CSI驱动提供了丰富的监控指标:

CSI指标收集

type MetricsManager struct {
    driverName    string
    operationCounters *prometheus.CounterVec
    operationDurations *prometheus.HistogramVec
    errorCounters *prometheus.CounterVec
}

// 监控指标示例
var csiOperations = prometheus.NewCounterVec(
    prometheus.CounterOpts{
        Name: "csi_operations_total",
        Help: "Total number of CSI operations by driver and operation type",
    },
    []string{"driver_name", "operation_type", "result"},
)

迁移与兼容性

Kubernetes提供了CSI迁移框架,支持将内置卷插件透明迁移到CSI:

迁移支持矩阵 | 内置插件 | CSI驱动 | 特性支持 | |---------|---------|---------| | AWSEBS | ebs.csi.aws.com | 完整支持 | | GCEPD | pd.csi.storage.gke.io | 完整支持 | | AzureDisk | disk.csi.azure.com | 完整支持 | | Cinder | cinder.csi.openstack.org | 完整支持 |

迁移配置示例

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: migrated-ebs
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  encrypted: "true"

CSI容器存储接口标准通过其模块化设计和标准化接口,为Kubernetes生态系统提供了强大、灵活且可扩展的存储解决方案。它不仅解决了存储供应商的集成问题,还为终端用户提供了统一的存储体验。

总结

Kubernetes存储管理系统通过Volume、PV/PVC、StorageClass和CSI等核心组件,构建了一套完整且强大的持久化数据解决方案。文章详细阐述了Volume的类型体系架构和生命周期管理机制,PV与PVC的核心抽象和绑定机制,StorageClass的动态配置能力,以及CSI标准的架构设计和实现原理。这些组件协同工作,为云原生应用提供了灵活、可靠、可扩展的存储能力,支持从简单的临时存储到复杂的企业级存储需求。通过标准化的接口和声明式的API,Kubernetes成功实现了存储资源的自动化管理和优化,为有状态应用在容器化环境中的稳定运行奠定了坚实基础。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值