Kubernetes工作负载

Kubernetes工作负载

工作负载控制器是什么

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

常用工作负载控制器:

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

控制器的作用:

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

在这里插入图片描述

Deployment详解

Deployment的功能:

管理Pod和ReplicaSet

  • 具有上线部署、副本设定、滚动升级、回滚等功能
  • 提供声明式更新,例如只更新一个新的Image

应用场景:网站、API、微服务
在这里插入图片描述

Deployment:部署

第一步:部署镜像

  • kubectl apply -f xxx.yaml
  • kubectl create deployment web --image=nginx:1.15
[root@master ~]# cat test.yaml 
---
apiVersion: apps/v1			// api版本
kind: Deployment			// 类型
metadata:
   name: syb				// 容器名字
   namespace: default		// 默认名称空间
spec:
  replicas: 3				// 复制成3个容器
  selector:
    matchLabels:
      app: busybox			// 标签
  template: 
    metadata: 
      labels:
        app: busybox		// 标签
    spec: 
      containers:
      - name: b1					
        image: busybox		// 使用镜像busybox
        command: ["/bin/sh","-c","sleep 9000"]		// 一直运行
        
[root@master ~]# kubectl apply -f test.yaml 
deployment.apps/syb created
[root@master ~]# kubectl get pod
NAME                   READY   STATUS              RESTARTS   AGE
syb-864fd4fb54-45j9h   1/1     Running             0          75s
syb-864fd4fb54-89kt4   1/1     Running             0          75s
syb-864fd4fb54-5k96l   0/1     ContainerCreating   0          75s

Deployment:滚动升级

第二步:应用升级(更新镜像三种方式)

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

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

滚动升级在K8s中的实现:

  • 1个Deployment
  • 2个ReplicaSet

在这里插入图片描述
滚动更新策略:

spec: 
  replicas: 3
  revisionHistoryLimit: 10 			# RS历史版本保存数量
  selector:
    matchLabels:
      app: web
  strategy:
    rollingUpdate: 
      maxSurge: 25%
      maxUnavaliable: 25%
    type: RollingUpdate
  • maxSurge:滚动更新过程中最大Pod副本数,确保在更新时启动的Pod数量比期望(replicsa)Pod数量最大多出25%
  • maxUnavailable:滚动更新过程中最大不可用Pod副本数,确保在更新时最大25%Pod数量不可用,即确保75%Pod数量是可用状态

实例

// 本地有镜像
[root@master ~]# docker images
REPOSITORY                    TAG       IMAGE ID       CREATED        SIZE
syblyw0806/httpd              latest      f61bb05k1b9a   11 days ago    92.3MB


// 创建四个httpd容器。名字都叫web
[root@master ~]# cat test2.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: web
  namespace: default
spec: 
  replicas: 4
  selector: 
    matchLabels: 
      app: httpd
  template: 
    metadata: 
      labels: 
        app: httpd
    spec: 
      containers:
        - name: httpd
          image: syblyw0806/httpd:latest
          imagePullPolicy: IfNotPresent
          
[root@master ~]# kubectl apply -f test2.yaml 
deployment.apps/web created

[root@master ~]# kubectl get pods
web-5d688b9745-7gx4g   1/1     Running             0          100s
web-5d688b9745-9hnxz   1/1     Running             0          100s
web-5d688b9745-ft6w9   1/1     Running             0          100s
web-5d688b9745-vmcbv   1/1     Running             0          100s

// 再次编写test2.yaml文件,设置maxSurge、maxUnavaliable
[root@master ~]# cat test2.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: syblyw0806/httpd:latest
          imagePullPolicy: IfNotPresent

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

// 查看发现暂未发生变化
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-5d688b9745-7gx4g   1/1     Running     0          10m
web-5d688b9745-9hnxz   1/1     Running     0          10m
web-5d688b9745-ft6w9   1/1     Running     0          10m
web-5d688b9745-vmcbv   1/1     Running     0          10m

// 我们去test2.yaml里面修改一下镜像
#其余内容不变
[root@master ~]# vim test2.yaml 
image: httpd		// 镜像修改就会更新

// 修改完之后应用
[root@master ~]# kubectl apply -f test2.yaml 
deployment.apps/web configured

// 发现停止了三个旧的web,启动了两个新的web和一个旧的web,还有两个新web正在创建
[root@master ~]# kubectl get pods
NAME                   READY   STATUS             	 RESTARTS   	AGE
web-5d688b9745-7gx4g   1/1     Terminating     		 0          	10m
web-5d688b9745-9hnxz   0/1     Running         	     0          	22m
web-5d688b9745-ft6w9   0/1     Terminating        	 0          	22m
web-5d688b9745-vmcbv   0/1     Terminating        	 0          	22m
web-f8bcfc88-bcvcd     0/1     Running 	 			 0          	92s
web-f8bcfc88-kkx4f     0/1     Running  	         0          	92s
web-f8bcfc88-w4dxx     1/1     ContainerCreating   	 0          	65s
web-f8bcfc88-x6q5z     1/1     ContainerCreating   	 0          	47s

// 最后变为四个新的web
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-f8bcfc88-bcvcd     1/1     Running     0          92s
web-f8bcfc88-kkx4f     1/1     Running     0          92s
web-f8bcfc88-w4dxx     1/1     Running     0          65s
web-f8bcfc88-x6q5z     1/1     Running     0          47s

Deployment:水平扩锁容

第三步:水平扩充容(启动多实例,提高并发)

  • 修改yanl里replicas值,再apply
  • kubectl scale deployment web --replicas=10

注:replicas参数控制Pod副本数量

实例:

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-f8bcfc88-bcvcd     1/1     Running     0          92s
web-f8bcfc88-kkx4f     1/1     Running     0          92s
web-f8bcfc88-w4dxx     1/1     Running     0          65s
web-f8bcfc88-x6q5z     1/1     Running     0          47s


// 创建10个容器
[root@master ~]# cat test2.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: web
  namespace: default
spec: 
  replicas: 10						// 复制成10个
  strategy: 
    rollingUpdate:
      maxSurge: 55%					// 最大可超出55%
      maxUnavailable: 50%			// 最大不可用50%
    type: RollingUpdate
  selector: 
    matchLabels: 
      app: httpd
  template: 
    metadata: 
      labels: 
        app: httpd
    spec: 
      containers:
        - name: httpd
          image: syblyw0806/httpd:latest
          imagePullPolicy: IfNotPresent
          
// 应用          
[root@master ~]# kubectl apply -f test2.yaml 
deployment.apps/web created

// 查看,发现10个容器已经创建好了,都已经运行了
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-5d688b9745-6dqcl   1/1     Running     0          63s
web-5d688b9745-bkmbf   1/1     Running     0          63s
web-5d688b9745-cpxkx   1/1     Running     0          63s
web-5d688b9745-gxjf6   1/1     Running     0          63s
web-5d688b9745-k2l2b   1/1     Running     0          63s
web-5d688b9745-ll5cc   1/1     Running     0          63s
web-5d688b9745-sqckx   1/1     Running     0          63s
web-5d688b9745-t578c   1/1     Running     0          63s
web-5d688b9745-txwh9   1/1     Running     0          63s
web-5d688b9745-z25kc   1/1     Running     0          63s

// 修改replicas值,实现水平扩缩容
#其余内容不变
[root@master ~]# vim test2.yaml 
replicas: 3

[root@master ~]# kubectl get pods
NAME                   READY   STATUS              			  RESTARTS   AGE
web-5d688b9745-6dqcl   1/1     Running     					  0          63s
web-5d688b9745-bkmbf   1/1     Running     					  0          63s
web-5d688b9745-cpxkx   1/1     Terminating     				  0          63s
web-5d688b9745-gxjf6   1/1     Terminating        			  0          63s
web-5d688b9745-k2l2b   1/1     Terminating   				  0          63s
web-5d688b9745-ll5cc   1/1     Terminating    				  0          63s
web-5d688b9745-sqckx   1/1     Terminating    				  0          63s
web-5d688b9745-t578c   1/1     Terminating     				  0          63s
web-5d688b9745-txwh9   1/1     Terminating    				  0          63s
web-5d688b9745-z25kc   1/1     Terminating    				  0          63s
web-f8bcfc88-hb8dz     0/1     ContainerCreating              0          5s
web-f8bcfc88-ldqt5     0/1     ContainerCreating              0          5s
web-f8bcfc88-r8zn7     0/1     ContainerCreating              0          5s

// 最后结果只剩3个
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
web-f8bcfc88-hb8dz     1/1     Running     0          3m44s
web-f8bcfc88-ldqt5     1/1     Running     0          3m44s
web-f8bcfc88-r8zn7     1/1     Running     0          3m44s

在这里插入图片描述

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>			
revisionHistoryLimit: 5/可以保留多个版本
[root@master ~]# vim test2.yaml
revisionHistoryLimit: 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           29s
web     3/3     3            3           16m

// 单个删除
[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           16m


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

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

Deployment:ReplicaSet

ReplicaSet控制器用途:

  • Pod副本数量管理,不断对比当前Pod数量与期望Pod数量
  • Deployment每次发布都会创建一个RS作为记录,用于实现回滚

kubectl get rs 查看RS记录

[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d688b9745   3         3         3       7m5s
web-f8bcfc88     0         0         0       6m33s

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-5d688b9745   3         3         3       7m5s
web-f8bcfc88     0         0         0       6m33s

// 修改镜像
#其余内容不变
[root@master ~]# vim test2.yaml 
image: httpd

// 应用
[root@master ~]# kubectl apply -f test2.yaml 
deployment.apps/web configured`在这里插入代码片`

[root@master ~]# kubectl get pods
web-5d688b9745-dpmsd   1/1     Terminating         0          11m
web-5d688b9745-q6dls   1/1     Terminating         0          11m
web-f8bcfc88-4rkfx     0/1     ContainerCreating   0          2s
web-f8bcfc88-6knsw     1/1     Running             0          2s
web-f8bcfc88-bd9zz     1/1     Running             0          2s

// 每一个版本对应一个RS,上一个版本被干掉了,新的版本会有新的Rs
[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d688b9745   0         0         0       12m
web-f8bcfc88     3         3         3       12m

ReplicaSet:由Deployment里面的relicas的参数控制的,我们不需要单独的定义这个控制器!

实例:

[root@node2 ~]# docker ps | grep web
4c938ad0c01d   dabbfbe0c57b                                        "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
4c938ad0c01d

[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d688b9745   0         0         0       17m
web-f8bcfc88     3         3         2       17m

// 等会他自己会启用
[root@master ~]# kubectl get rs
NAME             DESIRED   CURRENT   READY   AGE
web-5d688b9745   0         0         0       18m
web-f8bcfc88     3         3         3       17m

[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS      AGE
web-f8bcfc88-4rkfx     1/1     Running     2 (80s ago)   6m32s
web-f8bcfc88-6knsw     1/1     Running     0             6m32s
web-f8bcfc88-bd9zz     1/1     Running     0             6m32s

在这里插入图片描述

DameonSet

DameonSet功能:

  • 在每一个Node上运行一个Pod
  • 新加入的Node也同样会自动运行一个Pod

应用场景:网络插件(kube-proxy、calicao)、其他Agent

// 删除资源,容器也会被删除
[root@master ~]# kubectl delete -f test2.yaml 
deployment.apps "web" deleted

[root@master ~]# cat daemon.yaml
---
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             11 (4h36m ago)   6d4h
coredns-6d8c4cb4d-mp662          1/1     Running             11 (4h36m ago)   6d4h
etcd-master                      1/1     Running             13 (4h36m ago)   6d4h
kube-apiserver-master            1/1     Running             13 (4h36m ago)   6d4h
kube-controller-manager-master   1/1     Running             14 (4h36m ago)   6d4h
kube-flannel-ds-g9jsh            1/1     Running             11 (4h36m ago)   6d1h
kube-flannel-ds-qztxc            1/1     Running             11 (4h36m ago)   6d1h
kube-flannel-ds-t8lts            1/1     Running             13 (4h36m ago)   6d1h
kube-proxy-q2jmh                 1/1     Running             12 (4h36m ago)   6d4h
kube-proxy-r28dn                 1/1     Running             13 (4h36m ago)   6d4h
kube-proxy-x4cns                 1/1     Running             12 (4h36m ago)   6d4h
kube-scheduler-master            1/1     Running             14 (4h36m ago)   6d4h

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

// 这是系统相关的,普通用户一半不会用,也不会影响
所以你需要在每个节点都运行容器的时候,可以用DameonSet来执行:公共任务

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

// 所以节点都可以跑,除了master,master默认不可被调度
[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.244.2.219     node2.example.com   <none>           <none>
filebeat-d2psf                   1/1     Running   0                3m9s   10.244.1.141     node1.example.com   <none>           <none>

注意:资源创建成功,文件是可以删除的,资源一样运行,资源不会随着文件改变而改变,你想改变的时候就在写一个文件

Job 和 CronJob

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

  • 一次性执行

应用场景:离线数据处理,视频解码等业务

实例:

// 写一个job.yaml文件
[root@master ~]# cat job.yaml 
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template: 
    spec: 
      containers:
      - name: pi
        image: perl
        command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

// 运用job.yaml文件
[root@master ~]# kubectl apply -f job.yaml
job.batch/pi created

// 查看pod详细情况
在node2节点上面运行
[root@master ~]# kubectl get pods -o wide
NAME       READY   STATUS              RESTARTS   AGE     IP       NODE                NOMINATED NODE   READINESS GATES
pi-27xrt   0/1     ContainerCreating   0          9m20s   <none>   node2.example.com   <none>           <none>

// 去node2上面过滤
[root@node2 ~]# docker ps | grep pi
e55ac8842c89   registry.aliyuncs.com/google_containers/pause:3.6   "/pause"                 9 minutes ago   Up 9 minutes             k8s_POD_pi-27xrt_default_698b4c91-ef54-4fe9-b62b-e0abc00031fd_0

// 已经完成了
[root@master ~]# kubectl get pods
NAME       READY   STATUS              RESTARTS   AGE
pi-27xrt   0/1     Completed           0          22m

// 去node2节点上查看
[root@node2 ~]#  docker images | grep perl
perl                                                 latest    f9596eddf06f   3 days ago     890MB

// 成功创建
[root@master ~]# kubectl describe job/pi
Name:             pi
Namespace:        default
Selector:         controller-uid=5058b8e2-fc49-4247-9b5b-6f2b5df6dc67
Labels:           controller-uid=5058b8e2-fc49-4247-9b5b-6f2b5df6dc67
                  job-name=pi
Annotations:      batch.kubernetes.io/job-tracking: 
Parallelism:      1
Completions:      1
Completion Mode:  NonIndexed
Start Time:       Fri, 24 Dec 2021 23:15:29 +0800
Completed At:     Fri, 24 Dec 2021 23:15:56 +0800
Duration:         20m
Pods Statuses:    0 Active / 1 Succeeded / 0 Failed		// 看这里
......以下省略

CronJob用于实现定时任务,像Linux的Crontab一样

  • 定时任务

应用场景:通知、备份

实例:

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

// 写一个cronjob.yaml文件
[root@master ~]# cat cronjob.yaml 
---
apiVersion: batch/v1		# v1.23.1版本这里要这么编写
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1****"
  jobTemplate: 
    spec: 
      template: 
        spec: 
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date;echo Hello aliang
          restartPolicy: OnFailure

[root@master ~]# date
Fri Dec 24 11:58:50 CST 2021

// 运行计划任务
[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-27338645-xddbs   0/1     Completed   0          2m54s
hello-27338646-54jvb   0/1     Completed   0          114s
hello-27338647-ntnhq   0/1     Completed   0          54s

// 开始运行
[root@master ~]# kubectl get pods
NAME                   READY   STATUS              RESTARTS   AGE
hello-27338645-xddbs   0/1     Completed           0          3m16s
hello-27338646-54jvb   0/1     Completed           0          2m16s
hello-27338647-ntnhq   0/1     Completed           0          76s
hello-27338648-hlh49   0/1     ContainerCreating   0          16s

// 运行完成
[root@master ~]# kubectl get pods
NAME                   READY   STATUS      RESTARTS   AGE
hello-27338646-54jvb   0/1     Completed   0          2m54s
hello-27338647-ntnhq   0/1     Completed   0          114s
hello-27338648-hlh49   0/1     Completed   0          54s


// 创建成功
[root@master ~]# kubectl describe cronjob/hello
Events:
  Type    Reason            Age                     From                Message
  ----    ------            ----                    ----                -------
  Normal  SuccessfulCreate  3m27s (x133 over 135m)  cronjob-controller  (combined from similar events): Created job hello-27338944

注意:batch/v1beta1 CronJob 在 v1.21+ 中被弃用,在 v1.25+ 中不可用; 使用批处理/v1 CronJob。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值