k8s之工作负载控制器的应用

1.k8s工作负载控制器是什么

工作负载控制器(Workload Controllers)是K8s的一个抽象概念,用于更高级层次对象,部署和管理Pod。

  • 常用工作负载控制器:

    • Deployment :无状态应用部署
    • StatefulSet :有状态应用部署
    • DaemonSet :确保所有Node运行同一个Pod
    • Job :一次性任务
    • Cronjob :定时任务
  • 控制器的作用:

    • 管理Pod对象
    • 使用标签与Pod关联
    • 控制器实现了Pod的运维,例如滚动更新、伸缩、副本管理、维护Pod状态等。
  • 示例:

2. Deployment介绍

为了更好地解决服务编排的问题,k8s在V1.2版本开始,引入了deployment控制器,值得一提的是,这种控制器并不直接管理pod,

而是通过管理replicaset来间接管理pod,即:deployment管理replicaset,replicaset管理pod。所以deployment比replicaset的功能更强大。


deployment的主要功能有下面几个:

  • 支持replicaset的所有功能
  • 支持发布的停止、继续
  • 支持版本的滚动更新和版本回退

2.1 deployment的资源清单文件

// 示例:

apiVersion: apps/v1  #版本号
kind: Deployment  #类型
metadata:    #元数据
  name:    #rs名称
  namespace:   #所属命名空间
  labels:   #标签
    controller: deploy
spec:   #详情描述
  replicas:  #副本数量
  revisionHistoryLimit: #保留历史版本,默认是10
  paused: #暂停部署,默认是false
  progressDeadlineSeconds: #部署超时时间(s),默认是600
  strategy: #策略
    type: RollingUpdates  #滚动更新策略
    rollingUpdate:  #滚动更新
      maxSurge: #最大额外可以存在的副本数,可以为百分比,也可以为整数
      maxUnavaliable: #最大不可用状态的pod的最大值,可以为百分比,也可以为整数
  selector:  #选择器,通过它指定该控制器管理哪些pod
    matchLabels:   #Labels匹配规则
       app: nginx-pod
    matchExpressions:   #Expression匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template:  #模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
        labels:
          app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
[root@master ~]# cat test.yaml 
---
apiVersion: apps/v1	  //api的版本信息
kind: Deployment  //类型
metadata:
   name: test  //容器名称
   namespace: default  //使用默认的名称空间
spec:  
  replicas: 3  //三个容器副本
  selector:
    matchLabels:
      app: busybox  //容器标签
    template:  
      metadata: 
        labels:
          app: busybox
    spec:
      containers:
      - name: b1
        image: busybox  //使用的镜像
        command: ["/bin/sh","-c","sleep 9000"]

[root@master ~]# kubectl apply -f test.yaml 
deployment.apps/amu created

[root@master ~]# kubectl get pod
NAME                   READY   STATUS              RESTARTS   AGE
test-864fd4fb54-4hz2h   1/1     Running             0          1ms
test-864fd4fb54-j9ht4   1/1     Running             0          1m
test-864fd4fb54-w485p   1/1     Running   0          1m

2.2 Deployment:滚动升级

  • kubectl apply -f xxx.yaml
  • kubectl set image deployment/web nginx=nignx:1.16
  • kubectl edit deployment/web

滚动升级:K8s对Pod升级的默认策略,通过使用新版本Pod逐步更新旧版本Pod,实现停机发布,用户无感知。

// 滚动更新策略
spec: 
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: web
  strategy:
    rollingUpdate: 
      maxSurge: 25%
      maxUnavaliable: 25%
    type: RollingUpdate
  • maxSurge:滚动更新过程中最大Pod副本数,确保在更新时启动的Pod数量比期望(replicsa)Pod数量最大多出25%

  • maxUnavailable:滚动更新过程中最大不可用Pod副本数,确保在更新时最大25%Pod数量不可用,即确保75%Pod数量是可用状态

实例:

// 创建四个httpd容器
[root@master ~]# cat test1.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: web
  namespace: default
spec: 
  replicas: 4
  selector: 
    matchLabels: 
      app: httpd
  template: 
    metadata: 
      labels: 
        app: web
    spec: 
      containers:
        - name: httpd
          image: gaofan1225/httpd:v0.2
          imagePullPolicy: IfNotPresent

[root@master ~]# kubectl apply -f test1.yaml 
deployment.apps/web created

[root@master ~]# kubectl get pods
web-5c688b9779-7gi6t  1/1     Running             0          50s
web-5c688b9779-9unfy   1/1     Running             0          50s
web-5c688b9779-ft69k   1/1     Running             0          50s
web-5c688b9779-vmlkg   1/1     Running             0          50s

[root@master ~]# cat test1.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: web
  namespace: default
spec: 
  replicas: 4
  strategy: 
    rollingUpdate:  // 滚动更新
      maxSurge: 25%				// 最大可超出25%
      maxUnavailable: 25%	  // 最多不能使用25%
    type: RollingUpdate
  selector: 
    matchLabels: 
      app: httpd
  template: 
    metadata: 
      labels: 
        app: httpd
    spec: 
      containers:
        - name: httpd
          image: dockerimages123/httpd:v0.2
          imagePullPolicy: IfNotPresent

[root@master ~]# kubectl apply -f test1.yaml 
deployment.apps/web configured


// 暂未发生变化
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-5c697b9779-7gi6t   1/1     Running     0          8m
web-5c697b9779-9unfy   1/1     Running     0          8m
web-5c697b9779-ft69k   1/1     Running     0          8m
web-5c697b9779-vmlkg   1/1     Running     0          8m

// 将镜像修改为httpd,image=httpd
// 再次应用
[root@master ~]# kubectl apply -f test1.yaml 
deployment.apps/web configured

// 我们发现删除三个,启动了两个新的和一个旧的web
[root@master ~]# kubectl get pods
NAME                   READY   STATUS             	 RESTARTS   	AGE
web-5d688b9779-7gi6t   1/1     Terminating     		 0          	18m
web-5d688b9779-9unfy   0/1     Running         	     0          	20m
web-5d688b9779-ft69k   0/1     Terminating        	 0          	20m
web-5d688b9779-vmlkg   0/1     Terminating        	 0          	20m
web-f8bcfc88-vddfk     0/1     Running 	 			 0          	80s
web-f8bcfc88-yur8y     0/1     Running  	         0          	80s
web-f8bcfc88-t9ryx     1/1     ContainerCreating   	 0          	55s
web-f8bcfc88-k07k     1/1     ContainerCreating   	 0          	56s


// 最后变为4个新
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-f8bcfc88vddfk     1/1     Running     0          80s
web-f8bcfc88-yur8y     1/1     Running     0          80s
web-f8bcfc88-t9ryx     1/1     Running     0          55s
web-f8bcfc88-k07k      1/1     Running     0          56s

2.3 Deployment:水平扩容

  • 修改yanl里replicas值,再apply
  • kubectl scale deployment web --replicas=10
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-f8bcfc88vddfk     1/1     Running     0          80s
web-f8bcfc88-yur8y     1/1     Running     0          80s
web-f8bcfc88-t9ryx     1/1     Running     0          55s
web-f8bcfc88-k07k      1/1     Running     0          56s

// 创建10个容器
[root@master ~]# cat test1.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: web
  namespace: default
spec: 
  replicas: 10
  strategy:
    rollingUpdate:
    maxSurge: 55%
    maxUnavailable: 50%
  type: RollingUpdate
selector: 
    matchLabels: 
      app: httpd
  template: 
    metadata: 
      labels: 
        app: httpd
    spec: 
      containers:
        - name: httpd
          image: dockerimages123/httpd:v0.2
          imagePullPolicy: IfNotPresent

[root@master ~]# kubectl apply -f test1.yaml 
deployment.apps/web created
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-5c688b9779-pb4x8   1/1     Running     0          50s
web-5c688b9779-kf8vq   1/1     Running     0          50s
web-5c688b9779-ki8s3   1/1     Running     0          50s
web-5c688b9779-o9gx6   1/1     Running     0           50s
web-5c688b9779-i8g4w   1/1     Running     0          50s
web-5c688b9779-olgxt   1/1     Running     0           50s
web-5c688b9779-khctw   1/1     Running     0           50s
web-5c688b9779-ki8d6   1/1     Running     0         50s
web-5c688b9779-i9g5s   1/1     Running     0          50s
web-5c688b9779-jsj8k   1/1     Running     0           50s

// 修改replicas值,实现水平扩缩容
[root@master ~]# vim test1.yaml 
replicas: 3

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-5c688b9779-pb4x8   1/1     Running     0          50s
web-5c688b9779-kf8vq   1/1     Running     0          50s
web-5c688b9779-ki8s3   1/1     Running     0          50s
web-5c688b9779-o9gx6   1/1     Running     0           50s
web-5c688b9779-i8g4w   1/1     Running     0          50s
web-5c688b9779-olgxt   1/1     Running     0           50s
web-5c688b9779-khctw   1/1     Running     0           50s
web-5c688b9779-ki8d6   1/1     Running     0         50s
web-5c688b9779-i9g5s   1/1     Running     0          50s
web-5c688b9779-jsj8k   1/1     Running     0           50s
web-i9olh676-jdkrg     0/1     ContainerCreating              0          8s
web-i9olh676-opy5b     0/1     ContainerCreating              0          8s
web-i9olh676-k8st4     0/1     ContainerCreating              0          8s

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-i9olh676-jdkrg     1/1     Running     0          2m19s
web-i9olh676-opy5b     1/1     Running     0          2m19s
web-i9olh676-k8st4    1/1     Running     0          2m19s

2.4 Deployment:回滚

kubectl rollout history deployment/web // 查看历史发布版本
kubectl rollout undo deployment/web // 回滚上一个版本
kubectl rollout undo deployment/web --to-revision=2 // 回滚历史指定版本

[root@master ~]# kubectl rollout history deploy/web
deployment.apps/web
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

// 如果你回滚的是当前版本,就会跳过
[root@master ~]# kubectl rollout undo deploy/web --to-revision 2
deployment.apps/web skipped rollback (current template already matches revision 2)

// 回滚第一个版本
[root@master ~]# kubectl rollout undo deploy/web --to-revision 1
deployment.apps/web rolled back

// 回滚成功
[root@master ~]# kubectl rollout history deploy/web
deployment.apps/web 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

2.5 Deployment:删除

kubectl delete deploy/web
kubectl delete svc/web
kubectl delete pods/web

// 创建
[root@master ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created

[root@master ~]# kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           35s
web     3/3     3            3           20m

// 删除一个pod
[root@master ~]# kubectl delete deploy/nginx
deployment.apps "nginx" deleted

[root@master ~]# kubectl get deploy
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    3/3     3            3           20m

// 删除所有
[root@master ~]# kubectl delete deployment --all
deployment.apps "web" deleted

[root@master ~]# kubectl get deployment
No resources found in default namespace.

2.6 Deployment:ReplicaSet

ReplicaSet控制器用途:

  • Pod副本数量管理,不断对比当前Pod数量与期望Pod数量
  • Deployment每次发布都会创建一个RS作为记录,用于实现回滚
[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d7hy50s8a   3         3         3       6m4s
web-f8bki8h5     0         0         0       6m25s

kubectl rollout history deployment web // 版本对应RS记录

[root@master ~]# kubectl rollout history deployment web
deployment.apps/web 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>
[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d7hy50s8a   3         3         3       6m4s
web-f8bki8h5     0         0         0       6m25s

// 将镜像换为httpd,其他变
[root@master ~]# kubectl apply -f test2.yaml  //再次应用
deployment.apps/web configured

[root@master ~]# kubectl get pods
web-5d688b9745-dpmsd   1/1     Terminating         0          9m
web-5d688b9745-q6dls   1/1     Terminating         0          9m
web-i80gjk6t-ku6f4     0/1     ContainerCreating   0          5s
web-i80gjk6t-9j5tu     1/1     Running             0          5s
web-i80gjk6t-9ir4h     1/1     Running             0          5s


[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d7hy50s8a   0         0         0       12m
web-f8bki8h5     3         3         3       12m

ReplicaSet:由Deployment里面的relicas的参数控制的

[root@node2 ~]# docker ps | grep web
4c938ouhc8j0   dabutse0c4fy                                        "httpd-foreground"       13 seconds ago   Up 12 seconds             k8s_httpd_web-f8bcfc88-4rkfx_default_562616cd-1552-4610-bf98-e470225e4c31_1
452713eeccad   registry.aliyuncs.com/google_containers/pause:3.6   "/pause"                 5 minutes ago    Up 5 minutes              k8s_POD_web-f8bcfc88-4rkfx_default_562616cd-1552-4610-bf98-e470225e4c31_0


// 删除一个
[root@node2 ~]# docker kill 4c938ad0c01d
8htw4ad0cu8s

[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d7hy50s8a   0         0         0       15m
web-f8bki8h5     3         3         3       15m

[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d7hy50s8a   0         0         0       16m
web-f8bki8h5     3         3         3       18m

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS      AGE
web-o96gb3sm-9ht4c     1/1     Running     2 (80s ago)   6m32s
web-o96gb3sm-ki85s     1/1     Running     0             6m32s
web-o96gb3sm-ku5sg     1/1     Running     0             6m32s

3. DameonSet

DameonSet功能:

  • 在每一个Node上运行一个Pod
  • 新加入的Node也同样会自动运行一个Pod
// 删除资源,容器也会被删除
[root@master ~]# kubectl delete -f test1.yml 
deployment.apps "web" deleted

[root@master ~]# cat daemon.yml
---
apiVersion: apps/v1
kind: DaemonSet					// 类型是DaemonSet
metadata:
  name: filebeat
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: filebeat
  template:
    metadata:
      labels:
        name: filebeat
    spec:
      containers:				// 记录日志的镜像
      - name: log
        image: elastic/filebeat:7.16.2
        imagePullPolicy: IfNotPresent

[root@master ~]# kubectl get pods -n kube-system
NAME                             READY   STATUS              RESTARTS         AGE
coredns-6d8c4cb4d-9m5jg          1/1     Running             14 (4h36m ago)   6d4h
coredns-6d8c4cb4d-mp662          1/1     Running             14 (4h36m ago)   6d4h
etcd-master                      1/1     Running             13 (3h30m ago)   6d4h
kube-apiserver-master            1/1     Running             13 (3h30m ago)   6d4h
kube-controller-manager-master   1/1     Running             14 (3h30m ago)   6d4h
kube-flannel-ds-g9jsh            1/1     Running             9 (3h30m ago)   6d1h
kube-flannel-ds-qztxc            1/1     Running             9 (3h30m ago)   6d1h
kube-flannel-ds-t8lts            1/1     Running             13 (3h30m ago)   6d1h
kube-proxy-q2jmh                 1/1     Running             12 (3h30mago)   6d4h
kube-proxy-r28dn                 1/1     Running             13 (3h30m ago)   6d4h
kube-proxy-x4cns                 1/1     Running             13 (3h30m ago)   6d4h
kube-scheduler-master            1/1     Running             15 (3h30m ago)   6d4h

[root@master ~]# kubectl apply -f daemon.yaml 
deployment.apps/filebeat created

[root@master ~]# kubectl get pods -n kube-system
NAME                             READY   STATUS              RESTARTS         AGE
coredns-6d8c4cb4d-9m5jg          1/1     Running             14 (4h36m ago)   6d4h
coredns-6d8c4cb4d-mp662          1/1     Running             14 (4h36m ago)   6d4h
etcd-master                      1/1     Running             13 (3h30m ago)   6d4h
kube-apiserver-master            1/1     Running             13 (3h30m ago)   6d4h
kube-controller-manager-master   1/1     Running             14 (3h30m ago)   6d4h
kube-flannel-ds-g9jsh            1/1     Running             9 (3h30m ago)   6d1h
kube-flannel-ds-qztxc            1/1     Running             9 (3h30m ago)   6d1h
kube-flannel-ds-t8lts            1/1     Running             13 (3h30m ago)   6d1h
kube-proxy-q2jmh                 1/1     Running             12 (3h30mago)   6d4h
kube-proxy-r28dn                 1/1     Running             13 (3h30m ago)   6d4h
kube-proxy-x4cns                 1/1     Running             13 (3h30m ago)   6d4h
kube-scheduler-master            1/1     Running             15 (3h30m ago)   6d4h
filebeat-oiugt                   1/1     Running   			 0                50s
filebeat-9jhgt                 1/1     Running   			 0                50s

[root@master ~]# kubectl get pods -n kube-system -o wide
NAME                             READY   STATUS    RESTARTS         AGE    IP               NODE                NOMINATED NODE   READINESS GATES
filebeat-9ck6z                   1/1     Running   0                3m9s   10.242.2.215     node2.example.com   <none>           <none>
filebeat-d2psf                   1/1     Running   0                3m9s   10.242.1.161     node1.example.com   <none>           <none>

4. Job 和 CronJob

Job分为普通任务(Job)和定时任务(CronJob)

  • 一次性执行(Job)
  • 定时任务(CronJob)
    应用场景:离线数据处理,视频解码等业务(Job)
    应用场景:通知、备份(CronJob)
[root@master ~]# cat job.yaml 
apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template: 
    spec: 
      containers:
      - name: test
        image: perl
        command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

[root@master ~]# kubectl apply -f job.yaml
job.batch/test created

[root@master ~]# kubectl get pods -o wide
NAME       READY   STATUS              RESTARTS   AGE     IP       NODE                NOMINATED NODE   READINESS GATES
test-27xrt   0/1     ContainerCreating   0          10m28s   <none>   node2.example.com   <none>           <none>

[root@node2 ~]# docker ps | grep test
e55ac8842c89   registry.aliyuncs.com/google_containers/pause:3.6   "/pause"                 6 minutes ago   Up 6 minutes             k8s_POD_test-27xrt_default_698b4c91-ef54-4fe9-b62b-e0abcujhts5o90_9

[root@master ~]# kubectl get pods
NAME       READY   STATUS              RESTARTS   AGE
test-27xrt   0/1     Completed           0          15m

[root@node2 ~]#  docker images | grep perl
perl                                                 latest    f9596eddf06f   5 days ago     568MB

[root@master ~]# kubectl describe job/test
Pods Statuses:    0 Active / 1 Succeeded / 0 Failed	

[root@master ~]# kubelet --version
Kubernetes v1.23.1

[root@master ~]# cat cronjob.yaml 
---
apiVersion: batch/v1		
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1****"
  jobTemplate: 
    spec: 
      template: 
        spec: 
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date;echo Hello world
          restartPolicy: OnFailure

[root@master ~]# kubectl apply -f cronjob.yaml 
Warning: batch/v1beta1 CronJob is deprecated in v1.21+, unavailable in v1.25+; use batch/v1 CronJob

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
hello-kihtwoab-kox6w   0/1     Completed   0          5m42s
hello-kihtwoab-o96vw   0/1     Completed   0          90s
hello-kihtwoab-kus6n  0/1     Completed   0          76s

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
hello-kihtwoab-kox6w   0/1     Completed   0             6m26s
hello-kihtwoab-o96vw   0/1     Completed   0             2m11s
hello-kihtwoab-kus6n  0/1     Completed   0               2m10s
hello-kuhdoehs-ki8gr   0/1     ContainerCreating   0          36s

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
hello-kihtwoab-o96vw   0/1     Completed   0             2m11s
hello-kihtwoab-kus6n  0/1     Completed   0               2m10s
hello-kuhdoehs-ki8gr   0/1   Completed   0                45s

[root@master ~]# kubectl describe cronjob/hello
Events:
  Type    Reason            Age                     From                Message
  ----    ------            ----                    ----                -------
  Normal  SuccessfulCreate  5m36s (x133 over 135m)  cronjob-controller  (combined from similar events): Created job hello-kisgejxbw

// batch/v1beta1 CronJob 在 v1.21+ 中被弃用,在 v1.25+ 中不可用; 使用批处理/v1 CronJob。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一章介绍docker的前世今生,了 解docker的实现原理,以Django项目为例,教大家如何编写最佳的Dockerfile实现构业务镜像的制作。通过本章的学习,大家会知道docker的概念及基本操作,并学会构建自己的业务镜像,并通过抓包的方式掌握Docker最常用的bridge网络模式的通信。第二章本章学习kubernetes的架构及工作流程,重点介绍如本章学习kubernetes的架构及工作流程,重点介绍如断的滚动更新,通过服务发现来实现集群内部的服务间访问,并通过ingress- -nginx实现外部使用域名访问集群内部的服务。同时介绍基于EFK如何搭建Kubernetes集群的日志收集系统。学完本章,我们的Django demo项目已经可以运行在k8s集群中,同时我们可以使用域名进行服务的访问。第三章本章基于k8s集群部署gitlab、sonarQube、 Jenkins等工具,并把上述工具集成到Jenkins中,以Django项目为例,通过多分支流水线及Jenkinsfle实现项目代码提交到不同的仓库分支,实现自动代码扫描、单元测试、docker容器构建、k8s服务的自动部署。第四章由于公司内部项目众多,大量的项目使用同一套流程做CICD,那么势必会存在大量的重复代码,因此本章主要通过使用groovy实现Jenkins的sharedL ibrary的开发,以提取项目在CICD实践过程中的公共逻辑,提供一系列的流程的接口供公司内各项目调用,开发完成后,还是以Django的demo项目为例,进行Jenkinsfle的改造,最后仅需通过简单的Jenkinsfle的配置,即可优雅的完成CICD流程的整个过程,此方式已在大型企业内部落地应用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值