Kubernetes技术笔记-从理论到实践,轻松搭建K8s集群

目录

理论

一、Kubernetes简介

二、集群架构

(一)Master(管理节点)

功能

核心组件

(二)Node(计算节点)

功能

核心组件

(三)镜像仓库

功能

组件

三、集群规划

(一)部署方式

源码部署

容器部署

(二)配置环境要求

(三)主机准备

四、必要服务

(一)容器运行时(Runtime)

(二)Calico

五、服务端口        

六、配置流程

七、核心命令

kubeadm 

搭建

一、Master节点

(一)前期准备

(二)环境配置

(三)安装软件包

(四)容器运行时配置

(五)内核参数配置

(六)镜像管理

(七)Tab 键设置

(八)master 安装

(九)网络插件安装

(十)计算节点安装

二、Node节点

验证


理论

一、Kubernetes简介

  • 随着容器技术的不断发展,人们迫切需要一套更加高级且灵活的管理系统来对 Docker 及容器进行有效管理。Kubernetes(简称 K8s)正是在这样的需求背景下应运而生,它的出现成功解决了这一问题。
  • Kubernetes 这一名词源自希腊语,意为 “舵手” 或 “领航员”。K8s 是其常见的缩写形式,这种缩写方式取自首字母 K 和尾字母 s,中间的 8 代表着两者之间的 8 个字母。
  • K8s 由 Google 研发,其设计思想源于 Google 十多年前用于大规模容器管理的技术 Borg。2014 年 6 月,Google 正式对外发布并开源了 K8s。
  • K8s 作为一款开源的容器集群管理系统,具备容器集群自动化部署、自动扩缩容以及自动化维护等核心功能。

二、集群架构

(一)Master(管理节点)

功能
  • 提供集群的控制 :作为集群的 “大脑”,全面掌控整个集群的运行状态以及各类操作指令
  • 对集群进行全局决策 :根据集群资源状况、负载情况等,做出资源分配、任务调度等关键决策。
  • 检测和响应集群事件 :实时监测集群内部发生的各类事件,例如节点故障、Pod 异常等,并能够迅速做出响应处理,以保障集群的稳定运行。
核心组件
  • APIServer        
    • 整个系统的对外接口,供客户端和其它组件调用:它是集群与外部世界交互的 “桥梁”,所有针对集群的操作请求都必须先经过 APIServer。
    • 后端元数据存储于etcd中(键值数据库):主要负责将接收到的有关集群状态等数据信息存储到etcd,从而实现数据的持久化以及在集群内部的共享。
  • Scheduler
    • 负责对集群内部的资源进行分配和调度 :根据预先设定的调度策略和算法,将待运行的Pod 合理地分配到合适的 Node 节点之上,确保资源能够得到高效利用的同时,使任务在各节点之间保持均衡分布。
  • ControllerManager
    • 负责管理控制器,相当于"大总管":能够统一管控多种不同类型的控制器,像节点控制器、复制控制器等,确保整个集群依照预定的规则和状态稳定运行,有效维持集群的稳定性和一致性。
  • etcd       
    • 2013 年 6 月,CoreOS 团队推出的开源项目 :该项目在行业内具有较高的权威性和专业性。
    • Go 语言实现,是一种高可用的分布式键值(key-value)数据库 :凭借高性能的 Go 语言开发而成,具备良好的性能表现和可靠性。其分布式架构特点使其能够轻松满足大规模集群环境下的数据存储需求。
    • 在分布式系统中,用于解决各种服务的配置信息管理分享以及服务发现等问题 :于复杂的分布式系统环境当中,etcd 为服务配置信息供给了集中式的存储与管理方案,极大地方便了各服务之间进行配置信息的共享以及服务的发现过程。    
    • Kubernetes 在运行过程中产生的所有元数据均存储于 etcd 之中 :充当集群数据存储的核心仓库角色,有力地保障了集群状态数据的可靠存储以及快速访问需求。

(二)Node(计算节点)

功能
  • 运行容器的实际节点 :作为容器的宿主环境,直接承担起容器的运行任务。
  • 提供运行环境 :能够为容器提供包括硬件资源(例如 CPU、内存等)以及软件环境(例如操作系统、容器运行时等)在内的各类所需资源。
  • 在多个节点上运行,实现水平扩展 :借助多个 Node 节点之间的协同配合工作,达成集群的水平扩展能力,进而满足日益增长的业务需求以及高可用性要求。
核心组件
  • kubelet
    • 负责监视 Pod,涵盖创建、修改、删除等操作:是 Node 节点上的核心管理组件,与 Master  节点协同工作,确保 Pod 的生命周期管理操作得以准确无误地执行。
  • kube-proxy        
    • 主要职责是为 Pod 对象提供代理服务,实现 service 的通信以及负载均衡功能:借助网络代理技术,保障集群内部各服务之间通信的畅通无阻,并且可以根据实际的负载状况对流量进行合理的分配,有效提升服务的可用性以及整体性能表现。
  • Runtime    
    • 容器管理(Containerd) :高效管理容器的运行、停止、重启等操作,确保容器在 Node节点上稳定运行。

(三)镜像仓库

功能
  • 存储镜像 :集中存放各类应用程序对应的容器镜像,为容器的创建提供基础资源支撑。
  • 为节点提供镜像支持 :便于 Node 节点迅速拉取到所需的镜像,从而加速容器的启动以及部署流程。
组件
  • Registry :作为镜像的存储与分发核心组件,主要负责镜像的上传、下载以及存储管理等操作。
  • Harbor :具备丰富企业级功能特性的镜像仓库,能够提供镜像的安全管理、访问控制、镜像复制等高级功能,全方位满足企业生产环境对于镜像仓库的使用需求。

三、集群规划

Kubernetes官网Kubernetes中文官方文档

(一)部署方式

源码部署
  • 简介 :通过下载源码或编译好的二进制文件,手工添加参数启动服务。
  • 特点 :Kubernetes 采用证书认证方式,部署过程中需要创建大量证书。
容器部署
  • 简介 :官方将服务制作成镜像,用户只需下载镜像并启动即可。
  • 特点 :官方工具 kubeadm 采用这种方式,是推荐的部署方式。

(二)配置环境要求

  • 内核版本 :要求内核版本 >= 3.10,适用于 RHEL 7 及以上版本。
  • 最低配置 :至少需要 2CPU 和 2G 内存
  • 节点唯一性 :节点之间不可以有重复的主机名、MAC 地址或 product_uuid。
  • 防火墙要求 :需要卸载防火墙 firewalld
  • 禁用 swap :为了保证系统性能和 Kubernetes 的正常运行,需禁用 swap
  • 卸载软件 :卸载podman和cri-o避免和Docker及Containerd冲突。

(三)主机准备

我使用的Linux系统版本是Rocky Linux 8.6,如果和我的配置不一样,下载的软件需要换成和自己Linux系统版本适配的。

harbor仓库的搭建参考我的上一篇文章Docker技术笔记-从理论到实操

主机名IP地址角色配置
harbor192.168.88.3镜像仓库2CPU,4G内存
master192.168.88.4管理控制节点2CPU,4G内存
node-0001192.168.88.5计算节点2CPU,2G内存
node-0002192.168.88.6计算节点2CPU,2G内存
node-0003192.168.88.7计算节点2CPU,2G内存

四、必要服务

(一)容器运行时(Runtime)

  • 定义 :Kubernetes 集群节点的核心组件,负责管理和运行容器。
  • 现状 :Docker 因其复杂性,需要额外安装插件才能使用,已被 Containerd 取代为默认运行时。
  • 功能
    • 镜像管理 :包括拉取镜像和存储镜像。
    • 容器生命周期管理 :支持创建容器,以及启动、停止、删除容器和监控状态。
    • 资源隔离与限制 :通过 Namespace 和 Cgroups 实现。
    • 网络与存储配置 :涵盖网络配置和存储挂载。
    • 安全特性 :具备安全策略和沙箱隔离功能。
    • 通信机制 :Kubernetes 通过 CRI(Container Runtime Interface)与容器运行时进行通信。

(二)Calico

  • 简介 :Calico 是一种容器之间网络互通的解决方案,能够实现 OpenStack、Docker 等与 workloads(容器)之间的互连,并对容器进行隔离控制,同时设置访问策略。
  • 功能 :让不同节点上的容器实现互连互通,并支持设置访问策略。
  • 优势
    • 节约资源 :采用三层路由方法,抑制二层广播,减少资源开销且具有可扩展性。
    • 易于管理 :无隧道设计,workloads 之间路径更短更简单,配置更少,便于管理。
    • 依赖性少 :仅依赖三层路由可达。
    • 适配性广 :较少的依赖性使其能够适配所有 VM、Container、白盒或混合环境场景。
  • 关键作用 :作为 Kubernetes 网络插件(CNI)的必备组件,提供 Pod 网络通信和网络策略等功能,若缺少它,集群网络将无法正常工作。

五、服务端口        

服务名端口号作用
kubernetes6443用于所有组件的接口服务
etcd2379-2380作为核心数据库使用
kube-scheduler10259提供调度服务
kube-controller-manager10257负责控制器管理服务
kubelet10250作为节点代理服务运行
kube-proxy10256主要负责网络通讯与负载均衡

六、配置流程

  • 控制节点(master)配置软件仓库 -> 系统环境配置 -> 安装软件包 -> 配置内核参数 -> 导入 Kubernetes 镜像 -> 设置 Tab 键 -> master 安装
  • 计算节点(node)修改仓库配置文件 -> 系统环境配置 -> 安装软件包 -> 配置内核参数 -> 加入集群

七、核心命令

kubeadm 

  • config :用于镜像管理
  • init :执行集群初始化操作。
  • reset :用于还原和删除集群设置。
  • join :使计算节点能够加入集群。
  • token :负责 token 凭证管理。
    • delete :根据 token 名字删除指定 token。
    • create :
      •  --ttl=0 :设置 token 有效期为永久生效,在生产环境建议设置为 2h 短期有效。
      • --print-join-comand :直接输出完整的加入命令。
  • help :提供命令帮助信息。
  • 注:其它命令在本篇博客中没有或者很少使用,之后再写K8s相关的博客时统一再写。

    搭建

    一、Master节点

    (一)前期准备

    • 获取软件包
      • 清华大学开源软件镜像站下载部署 K8s 集群和 Runtime 所需的软件包(cri-tools-1.29.0、kubeadm-1.29.2、kubectl-1.29.2、kubelet-1.29.2、kubernetes-cni-1.3.0)。

    • 配置 YUM 仓库 : 参考我的上一篇文章Docker技术笔记-从理论到实操中的Docker部署中的YUM仓库搭建流程。
      • 新建:安装vsftpd和createrepo软件包 -> 修改配置文件 ->  设置开启自启 -> 在/var/ftp/目录下新建K8s目录 -> 将下载的软件包移动到K8s目录下 -> 生成仓库清单文件 -> 修改YUM仓库配置文件 -> 更新YUM缓存。
      • 延续:在/var/ftp/目录下新建K8s目录 -> 将下载的软件包移动到K8s目录下 -> 生成仓库清单文件 --> 修改YUM仓库配置文件 -> 更新YUM缓存 。

    (二)环境配置

    • 禁用 firewalld 和 swap
      • sed '/swap/d' /etc/fstab &&  setenforce 0  && swapoff -a  && yum -y remove firewalld  && yum -y remove podman cri-o//禁用 swap 交换空间和SELINUX并卸载防火墙 firewalld,避免对集群网络通信造成干扰。卸载podman和cri-o避免和Docker及Containerd冲突。
    • 配置主机名解析
      vim /etc/hosts  
      192.168.1.3 harbor
      192.168.1.4 master
      192.168.1.5 node-0001
      192.168.1.6 node-0002
      192.168.1.7 node-0003
      //在文件中添加 master 主机以及所有计算节点的主机名解析,确保各节点间能够通过主机名正确通信。

    (三)安装软件包

    yum -y install kubeadm kubectl kubelet containerd.io ipvsadm ipset iproute-tc 
    //安装上述准备好的软件包,为集群部署奠定基础。
    软件包作用
    kubeadm 集群配置工具,用于初始化主节点添加工作节点以及升级集群
    kubelet在集群每个节点上运行的守护进程,负责管理容器生命周期、健康检查以及控制平面通信
    kubectl Kubernetes API 交互的命令行工具,用于部署应用和查看资源状态
    containerd.io容器管理软件(Runtime 容器运行时),负责创建、运行和管理容器,类似于 Docker
    ipvsadm IPVS 负载均衡管理工具,配合 kube-proxy 的 IPVS 模式使用
    iproute-tc 网络流量管理工具,用于管理网络策略
    ipset IP 地址管理工具,优化 IPVS 规则管理

    (四)容器运行时配置

    • 生成配置文件
      containerd config default > /etc/containerd/config.toml 
      //输出 containerd 的默认配置模板至 /etc/containerd/config.toml 文件,定义 containerd 运行时行为,包括镜像仓库和存储驱动等关键设置。
    • 修改配置文件 /etc/containerd/config.toml
      • 指定基础镜像61 行设置 sandbox_image = "harbor:443/k8s/pause:3.9" //指定 Kubernetes Pod 的基础镜像为私有仓库中的镜像。
      • 启用非特权用户支持125 行添加 SystemGroup = true //允许非 root 用户组访问 system-cgroup,提升兼容性,避免权限问题。
      • 配置镜像加速154 行配置镜像加速规则,添加以下行[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] 
        • endpoint = ["https://192.168.88.3:443"]
      • [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor:443"] 
        • endpoint = ["https://192.168.88.3:443"]  //将 docker.io 的镜像拉取请求重定向到私有 Harbor 仓库,添加访问地址 ,并为自定义仓库 harbor:443 指定访问地址参数 
      • [plugins."io.containerd.grpc.v1.cri".registry.confgs."192.168.88.3:443"]
        • [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.88.3:443".tls]
          • insecure_skip_verify = true  //跳过 HTTPS 证书验证(生产环境不推荐此设置)
        • [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.88.3:443".auth]
          • username = "admin"  
          • password = "harbor" //和自己设置的harbor仓库密码一致
    • 启用服务 
      systemctl enable --now kubelet containerd 

    (五)内核参数配置

    • 加载内核模块
      • vim /etc/modules-load.d/containerd.conf
        • 添加br_netfilterxt_conntrack 两行内容 //加载 br_netfilerxt_conntrack 内核模块。br_netfiler Linux 网桥支持 Netfiler 框架,允许 Kubernetes 在网桥设备上应用 iptables 规则,实现 Service 负载均衡和网络策略;xt_conntrack 提供连接跟踪功能,支持 kube-proxy 的会话保持和 NetworkPolicy 实现。
          systemctl start systemd-modules-load.service //立即加载配置的内核模块。
    • 设置内核参数
      vim /ettc/sysctl.d/99-kubernetes-cri.conf //添加以下内核参数:
          net.ipv4.ip_forward = 1  
          //启用 IPv4 数据包转发功能,实现路由功能。
          
          net.bridge.bridge-nf-call-iptalbes = 1 
          net.bridge.bridge-nf-call-ip6tables = 1  
          //强制网桥流量经过 iptables 规则,保障 kube-proxy 的 Service 负载均衡和 NetworkPolicy 规则生效。
          
          net.netfiler.nfs_conntrack_max = 100000  
          //增大连接跟踪表的最大条目数,避免因默认值过小导致新连接被丢弃,引发网络间歇性中断。
      
      sysctl -p /etc/sysctl.d/99-kubernetes-cri.conf  //使内核参数配置立即生效。

    (六)镜像管理

    • 导入 k8s 镜像 :提前准备 k8s 的镜像,通过能连接国外网的服务器下载镜像到本地或通过国内的镜像网站直接拉取相关的镜像。
    • 安装和配置 Docker
      yum -y install docker-ce
      vim /etc/docker/daemon.json //添加镜像加速及私有仓库地址和不安全仓库配置
      {
          "registry-mirrors":["https://harbor:443","https://docker.m.daocloud.io"],
          "insecure-registries":["harbor:443"]
      }
      
      sysrtemctl enable --now docker && docker info  //启动 docker 并验证配置。
    • 上传镜像到 harbor 仓库
      docker login harbor:443 -u 用户名 --password 密码 
      //登录 harbor 仓库,如通过用户名admin和密码harbor登录。
      • 浏览器登录harbor仓库新建k8s项目
      • 阿里云镜像网站拉取相关镜像
        docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.29.2
        docker pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.29.2
        docker pull registry.aliyuncs.com/google_containers/kube-proxy:v1.29.2
        docker pull registry.aliyuncs.com/google_containers/etcd:3.5.10-0
        docker pull registry.aliyuncs.com/google_containers/coredns:v1.11.1
        docker pull registry.aliyuncs.com/google_containers/pause:3.9
        docker pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.29.2
        docker images | while i t _;do  //上传镜像
            [[ "${t}" == "TAG" ]] && continue  //跳过标题行
            [[ "${i} =~ ^"harbor:443/".+ ]] && continue //跳过已上传镜像
            docker tag ${i}:${t| habor:443/k8s/${i##*/}:${t} //提取镜像名
            docker push harbor:443/k8s/${i##*/}:${t}
            docker rmi ${i}:${t} habor:443/k8s/${i##*/}:${t}
        done
      • 避免上传已存在的镜像,上传后删除已上传和在镜像仓库中已存在的镜像。
      • 也可手动逐个上传(不推荐此方式)
      docker  tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.29.2  harbor:443/k8s/registry.aliyuncs.com/google_containers//kube-apiserver:v1.29.2 && docker push harbor:443/k8s/registry.aliyuncs.com/google_containers//kube-apiserver:v1.29.2

    (七)Tab 键设置

    source <(kubeadm completion bash | tee /etc/bash_completion.d/kubeadm)
    source <(kubectl completion bash | tee /etc/bash_completion.d/kubectl)  
    //为 kubeadm 和 kubectl 设置 Tab 键自动补全功能(<和(之间不能有空格,格式要求),提升命令行操作效率。

    (八)master 安装

    • 修改配置文件
      vim /root/init.yaml 
      //通过 " kubeadm config print init-defaults > init.yaml "命令自动生成控制节点的配置文件模板,也可以从文档和社区中获取模板修改,并根据需求进行修改,指定 APIServer 的广播地址等关键参数。
      
          第1行前添加 ---
          第13行修改 advertiseAddress: 192.168.88.4 
          //指定APIServer的广播地址,其它节点连接master的地址,使用master主机节点地址
          第16行修改 criSocket: unix:///run/containerd/containerd.sock
          第18行修改 name: master
          第31行修改 imageRepository: harbor:443/k8s  
          第33行修改 kubernetesVersion: 1.29.2    
          第36行修改 podSubnet: 10.244.0.0/16 ,在下一行并与该行对齐的添加serviceSubnet:         10.245.0.0/16
          第38行后添加以下内容
          ---
          kind: KubeProxyConfiguration
          apiVersion: kubeproxy.config.k8s.io/v1alpha1
          mode: ipvs
          ipvs:
            strictARP: true
          ---
          kind: KubeletConfiguration
          apiVersion: kubelet.config.k8s.io/v1beta1
          cgroupDriver: systemd
    • 预检环境
      kubeadm init --config=init/init.yaml --dry-run 2>error.log && cat error.log 
      //测试系统环境,提前发现潜在问题,确保初始化过程顺利进行。
      
      rm -rf error.log /etc/kubernetes/tmp 
      //删除预检生成的临时文件和错误文件,确保初始化环境干净 避免旧文件干扰正式初始化过程。
      
      kubeadm config images pull --image-repository=192.168.88.88:443/k8s --config=init.yaml -v=5 
      //建议在正式初始化前通过该命令验证能不能正常拉取镜像(按理是可以的,我自己试过了)。
    • 正式初始化
      kubeadm init --config=init/int.yaml | tee init/init.log 
      //启动 master 节点初始化过程,并将初始化日志保存至文件,方便后续问题排查和审计。
    • 管理授权
      mkdir $HOME/.kube && \
      cp -i /etc/kubernetes/admin.conf $HOME/.kube/config && chown $(id -u):$(id -g) $HOME/.kube/config  
      
      //解释
      //创建kubectl配置目录,并复制管理员配置文件到该目录下,设置当前用户权限(可以避免不同发行版本的用户同id不同用户名的问题),使 kubectl 能够通过该配置文件管理集群。
    • 验证安装结果
      kubectl get nodes 
      //检查 master 节点是否成功注册(此时状态显示NotReady是正常的),确认集群控制平面已正常运行。

    (九)网络插件安装

    • 准备插件镜像
      • 准备插件存放目录,从官方下载或通过 Docker 拉取插件镜像,也可利用离线包提供插件镜像。
    • 下载镜像
      docker pull calico/kube-controllers:v3.26.4
      docker pull calico/cni:v3.26.4
      docker pull calico/node:v3.26.4
    • 上传镜像
      • 浏览器登录harbor仓库新建calico项目。
        docker images | while read i t _;do 
            [[ "${t}" == "TAG" ]] && continue  //跳过标题行
            [[ "${i}" =~ ^"harbor:443/".+ ]] && continue //跳过已上传镜像
            docker tag ${i}:${t} harbor:443/calico/${i##*/}:${t} //提取镜像名
            docker push harbor:443/calico/${i##*/}:${t}
            docker rmi ${i}:${t} harbor:443/calico/${i##*/}:${t} 
        done  
        //执行脚本导入镜像并上传至私有 harbor 仓库,确保镜像地址正确转换为私有仓库地址,支持离线环境部署和版本控制。
    • 安装 calico
      curl -L https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/calico.yaml -o calico.yaml 
      //下载config.yaml文件
      
      sed -ri 's,^(\s*image: )(.*/)?(.+),\1 harbor:443/calico/\3,' calico.yaml 
      //修改配置文件,将镜像地址替换为私有仓库地址。
          4642行 image: harbor:443/calico/cni:v3.26.4
          4670行 image: harbor:443/calico/cni:v3.26.4
          4713行 image: harbor:443/calico/node:v3.26.4
          4739行 image: harbor:443/calico/node:v3.26.4
          4956行 image: harbor:443/calico/kube-controllers:v3.26.4
      
      kubectl apply -f calico.yaml 
      //应用 Calico 配置,完成网络插件安装,保障集群网络通信正常。

    (十)计算节点安装

    • 直接获取凭证(推荐方式)
      kubeadm token list 
      //查看可用 token 列表。
      
      kubeadm token delete 默认 token  
      //删除默认 token(复制TOEKN下的值放在默认token的位置,默认有效期为 24 小时)。
      
      kubeadm token create --ttl=0 --print-join-command 
      //创建新的 token 并记录返回的命令,获取 token 及其 hash 值,用于计算节点加入集群(直接在对应的集群下输入该命令显示出来的命令)。
    • 计算获取凭证
      openssl  -x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der | openssl dgst -sha256 -hex 
      
      //解释
      //通过openssl计算token的hash值,提取 CA 证书公钥,将其转换为 DER (二进制)格式并计算 SHA256 哈希值(十六进制),验证 token 的 hash 值,以确保计算节点加入集群过程的安全性和正确性。

    二、Node节点

    • 准备相应配置的虚拟机 ,并按以下步骤操作: 修改YUM仓库配置文件 -> 同Master节点一样进行Master节点的环境配置、安装软件包、容器运行时配置、内核参数配置步骤
    • rsync -av 192.168.88.4:/etc/containerd/config.toml /etc/containerd/config.toml //通过rsync将master节点的config.toml直接传到node节点中,减少操作量
      kubeadm join master节点:端口 --token token值 --discovery-token-ca-cert-hash sha256:计算得来的ca证书hash值 
      //通过在master节点计算获取的凭证或直接复制直接获取凭证中的加入命令到Node节点执行。
    • 在三台节点重复上述两个步骤。

    验证

    kubectl -n kube-system get pods //验证容器工作状态
    kubectl get nodes //验证节点工作状态
    • 最终结果

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值