Kubernetes入门到实践 (二) Kubeadm安装Kubernetes集群

文章目录


一、前言

  在上一篇文章中已经对Kubernetes 与 yum安装Kubernetes集群 进行了介绍和讲解,也提到了Kubernetes集群的五种安装方式,由于yum安装Kubernetes的版本固定为1.5.2,不能安装最新版本,所以在生产环境中,一般很少使用yum方式来进行Kubernetes集群的安装。在生产环境中,用的最多的两种安装方式是:kubeadm安装 和 二进制安装,接下来我们就来讲解一下如何使用kubeadm方式安装Kubernetes集群。



1、安装前的环境准备 (三个节点都需要执行如下操作)

1.1、需要准备三台Linux虚拟机
主机名称节点名称IP地址cpu (处理器数量)内存系统及内核
k8s-mastermaster192.168.198.14522GCentOS7.x,内核版本至少为3.10及以上
k8s-node1node1192.168.198.14622GCentOS7.x,内核版本至少为3.10及以上
k8s-node2node2192.168.198.14722GCentOS7.x,内核版本至少为3.10及以上

1.2、修改主机名称
//1、查看当前主机的主机名称
hostname

//2、修改当前主机的主机名称
hostnamectl set-hostname 主机名称

这里以修改master节点的主机名为例 (node1 和 node2节点与修改master节点的主机名类似,只不过需要把k8s-master 替换为k8s-node1 和 k8s-node2即可)


1.3、配置ip地址 与 主机名的映射关系
//1、编辑hosts文件
vim /etc/hosts

//2、配置映射关系
192.168.198.145 k8s-master
192.168.198.146 k8s-node1
192.168.198.147 k8s-node2

这里以配置master节点的ip地址 与 主机名的映射关系为例 (node1 和 node2节点与配置master节点的ip地址 与 主机名的映射关系相同)


1.4、关闭firewalld防火墙 和 SELinux

firewalld会影响Docker的网络功能,SELinux是2.6+版本的Linux内核中提供的强制访问控制系统,在很大程度上加强了Linux的安全性,但是它会影响Kubernetes的某些组件功能,所以我们需要在安装部署前将其禁用掉

//-----------------------------------关闭Firewalld防火墙
//1、停止firewalld服务
systemctl stop firewalld

//2、禁止firewalld开机启动
systemctl disable firewalld

//3、列出所有iptables规则
iptables -L



//-----------------------------------关闭SELinux
//1、临时关闭
setenforce 0

//2、永久关闭SELinux
sed -i "s/^SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

//3、查看SELinux状态
sestatus




1.5、关闭swap分区 (为了提高k8s的性能,建议关闭swap分区)

由于kubernetes的想法是将实例紧密包装到尽可能接近100%,所有的部署应与CPU或者内存限制固定在一起,所以如果调度一个pod程序发送到一台机器上时,它不应该使用交换,因为这会减慢其运行速度,所以关闭swap主要是为了性能考虑

//1、临时关闭 swap分区
swapoff -a

//2、永久关闭
sed -ri 's/.*swap.*/#&/' /etc/fstab

//3、查看swap分区是否已经关闭,若swap一行都显示0,则表示关闭成功
free -m



1.6、同步系统时间 (多个节点之间强烈建议同步时间)

更多详细信息请看:CentOS7使用Chrony实现时间同步

1.6.1、安装chrony服务
yum install –y chrony




1.6.2、启动并加入开机自启
// 启动chrony服务
systemctl start chronyd

// 设置开机自启
systemctl enable chronyd

// 查看chrony服务状态
systemctl status chronyd



1.6.3、修改 /etc/chrony.conf配置文件
//1、编辑 /etc/chrony.conf配置文件
vim /etc/chrony.conf

//2、配置阿里云的ntp服务
/**
 * 注释掉默认的四个ntp服务器,因为该服务器同步时间略慢
 **/
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

/**
 * 格式为:server 服务器ip地址 iburst 
 * 添加阿里云的ntp服务器,可以多写几个ntp服务器,防止第一个服务器宕机,备用的其他ntp服务器可以继续进行时间同步
 * ip地址为服务器ip地址,iburst代表的是快速同步时间 
 **/  
server ntp1.aliyun.com iburst
server ntp2.aliyun.com iburst
server ntp3.aliyun.com iburst




1.6.4、重启chrony服务
//重启chrony服务
systemctl restart chronyd

// 查看chrony服务状态
systemctl status chronyd



1.7、配置内核参数,将桥接的IPv4流量传递到iptables的链上
//1、编写kubernetes.conf配置
vim /etc/sysctl.d/kubernetes.conf

//2、填写如下内容
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720

-------------------------解释-------------------------
net.bridge.bridge-nf-call-iptables=1:开启ipv4的过滤规则
net.bridge.bridge-nf-call-ip6tables=1:开启iptables中ipv6的过滤规则
net.ipv4.ip_forward=1:开启服务器的路由转发功能
vm.swappiness=0:禁止使用swap 空间,只有当系统OOM 时才允许使用它
vm.overcommit_memory=1:不检查物理内存是否够用
vm.panic_on_oom=0:开启OOM
net.ipv6.conf.all.disable_ipv6=1:禁止ipv6

//3、执行命令,使其配置文件生效
modprobe br_netfilter
sysctl -p /etc/sysctl.d/kubernetes.conf



可以看到最后一行提示为:sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory,这是因为我们当前3.10版本的CentOS内核中,不存在该文件,在后面操作中,我将会升级CentOS内核,升级之后的CentOS内核将包含该文件,所以这里我们暂时忽略该提示


1.8、开启kube-proxy的ipvs前置条件

从kubernetes的1.8版本开始,kube-proxy引入了ipvs模式,ipvs模式与iptables同样基于Netfilter,但是ipvs模式采用的是hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能

//1、安装ipvsadm 和 ipset
yum -y install ipvsadm ipset

//2、编辑ipvs.modules配置文件,使其永久生效
vim /etc/sysconfig/modules/ipvs.modules

//3、填写如下内容
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4

//4、设置文件权限
chmod 755 /etc/sysconfig/modules/ipvs.modules

//5、查看是否已经正确加载所需的内核模块
bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4




1.9、升级CentOS7的内核版本

CentOS内核升级的官方文档:http://elrepo.org/tiki/tiki-index.php

Docker官方对OverlayFS 和 内核版本的要求说明:https://docs.docker.com/storage/storagedriver/overlayfs-driver/

Docker使用OverlayFS作为存储驱动程序,同时Docker为OverlayFS提供了两个存储驱动程序:原始的overlay 和 更新、更稳定的overlay2,但是Docker官方建议如果使用OverlayFS,请使用overlay2驱动程序而不是overlay驱动程序,因为overlay2驱动程序在inode利用率方面更为有效。要使用overlay2驱动程序,就需要Linux内核的版本4.0或更高版本,或者使用3.10.0-514及更高版本的RHEL或CentOS

1.9.1、查看CentOS的内核版本
//1、查看内核版本
uname -r

//2、显示内核版本信息如下
3.10.0-693.el7.x86_64

在这里插入图片描述
可以看到centos7 的内核版本,虽然满足条件 (在3.10.0-514之上),但是其内核版本还是比较低的,为了更好的运行docker和kubernetes,建议对centos7的内核进行升级

1.9.2、安装ELRepo 和 kernel
//1、载入公钥
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

//2、安装ELRepo
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm

//3、安装内核 kernel
yum --enablerepo=elrepo-kernel install -y kernel-ml-devel kernel-ml




1.9.3、查看新安装的内核完整名称
//1、查看已安装的内核版本
rpm -qa | grep -i kernel

//2、 查找新安装的内核完整名称
cat /boot/grub2/grub.cfg | grep menuentry


可以看到,使用cat /boot/grub2/grub.cfg | grep menuentry命令,输入的第一行内容中包含新安装的内核完整名称信息,其名称为CentOS Linux (5.5.7-1.el7.elrepo.x86_64) 7 (Core)

1.9.4、更改CentOS7默认的系统内核版本

方式一:

//1、更改系统内核版本为最新安装版本
grub2-set-default 'CentOS Linux (5.5.7-1.el7.elrepo.x86_64) 7 (Core)'

//2、查看默认启动内核是否更换成功
grub2-editenv list

//3、重启系统
reboot



方式二:

//1、更改系统内核版本为最新安装版本
grub2-set-default 0 

//2、查看默认启动内核是否更换成功
grub2-editenv list

//3、重启系统
reboot

提示:由于升级后内核版本是往前面插入的,前面在查看新安装的内核完整名称时,我们也看到新安装的内核信息在第一行输出,所以设置启动顺序为0,即可更改为新内核版本



1.9.5、查看系统内核版本是否设置成功
uname -r



1.10、安装 docker
1.10.1、安装wget
yum -y install wget



1.10.2、配置阿里云的docker源
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo



1.10.3、指定docker-ce版本安装
//1、查询18.09版的docker-ce和docker-ce-cli
yum  list available docker-ce* --showduplicates|grep 18.09

//2、安装指定版本的docker-ce和docker-ce-cli
yum install -y docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io

或

//安装最新版本
yum install -y docker-ce docker-ce-cli containerd.io



1.10.4、设置docker开机自启和启动docker,并查看其版本
//1、设置docker开机自启 和 启动docker
systemctl enable docker && systemctl start docker

//2、查看docker版本
docker --version


1.10.5、编辑daemon.json配置文件

阿里云镜像加速器地址获取教程:https://blog.csdn.net/qq_39135287/article/details/101012149#10__150

kubernetes官方安装docker的daemon.json配置文件参考:https://kubernetes.io/docs/setup/production-environment/container-runtimes/

//1、编辑daemon.json配置文件
vim /etc/docker/daemon.json

//2、添加如下内容
{
  "registry-mirrors": ["https://m0p0xxqj.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}

//3、创建一个docker.service.d目录,用于存放docker的配置文件
mkdir -p /etc/systemd/system/docker.service.d



1.10.6、重新加载daemon.json配置文件 并 重启docker服务
//1、重新加载daemon.json配置文件
systemctl daemon-reload

//2、重启服务器
systemctl restart docker



1.11、安装kubeadm、kubelet 和 kubectl
1.11.1、配置阿里云的Kubernetes源
//1、编辑kubernetes.repo文件
vim /etc/yum.repos.d/kubernetes.repo

//2、添加如下内容
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg


解释:
enable=1:表示启用这个源
gpgcheck=1:表示对这个源下载的rpm包进行校验
repo_gpgcheck=0:某些安全性配置文件会在 /etc/yum.conf 内全面启用 repo_gpgcheck,以便能检验软件库中数据的加密签署,如果repo_gpgcheck设置为1,会进行校验,就会出现报错[Errno -1] repomd.xml signature could not be verified for kubernetes,所以这里设为0



1.11.2、安装kubeadm、kubelet 和 kubectl

提示:由于版本更新频繁,这里指定版本号部署

yum install -y kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0



1.11.3、修改kubelet配置文件,关闭swap
//1、编辑kubelet配置文件
vim /etc/sysconfig/kubelet

//2、添加 --fail-swap-on=false参数
KUBELET_EXTRA_ARGS="--fail-swap-on=false"



1.11.4、设置kubelet为开机自启
systemctl enable kubelet



2、部署Kubernetes Master节点 (在master节点上执行)

2.1、提前下载初始化master节点所需镜像
2.1.1、查看安装kubernetes v1.23.0需要哪些镜像
kubeadm config images list --kubernetes-version=v1.23.0



2.1.2、编写镜像下载脚本并设置可执行权限
//1、编写脚本
vim k8s-image-download.sh

//2、为脚本设置可执行权限
chmod +x k8s-image-download.sh

//3、查看脚本是否已经拥有可执行权限
ll k8s-image-download.sh



k8s-image-download.sh 脚本内容如下

#!/bin/bash
if [ $# -ne 1 ];then
    echo "The format is: ./`basename $0` kubernetes-version"
    exit 1
fi

version=$1
images=`kubeadm config images list --kubernetes-version=${version} | awk -F '/' '{print $2}'`

for imageName in ${images[@]} ; do
  docker pull registry.aliyuncs.com/google_containers/$imageName
  docker tag registry.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
  docker rmi registry.aliyuncs.com/google_containers/$imageName
done



2.1.3、执行脚本,下载镜像
./k8s-image-download.sh v1.23.0


2.2、初始化master节点

提示:--apiserver-advertise-address需要改成你自己master节点的ip地址

kubeadm init \
--apiserver-advertise-address=192.168.198.145 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.23.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16



解释:
--apiserver-advertise-address:指定用master节点的ip地址 与 Cluster的其他节点通信。

--image-repository:Kubenetes默认Registries地址是 k8s.gcr.io,一般在国内并不能访问 gcr.io,
                    可以将其指定为阿里云镜像地址:registry.aliyuncs.com/google_containers。

--kubernetes-version=v1.23.0:指定要安装kubernetes的版本号。
--service-cidr:指定Service网络的范围,即负载均衡VIP使用的IP地址段。
--pod-network-cidr:指定Pod网络的范围,即Pod的IP地址段。

1、可以看到程序停止在[preflight] You can also perform this action in beforehand using 'kubeadm config images pull',这是因为它在下载kubernetes相关组件的镜像,所以耐心等待一段时间


2、可以看到安装成功之后,红色方框框起来的两部分内容,在后面的安装过程中需要用上,第一部分内容是用来配置kubectl工具,第二部分内容是在node节点加入时需要此信息

//记录生成token和秘钥,在node节点加入时需要此信息
kubeadm join 192.168.198.145:6443 --token tgmuix.lj2v3b6ogev7yjp6 \
    --discovery-token-ca-cert-hash sha256:2328518d9636ebbe4cdc05f1750e2e89071ef7ed98561f16a1b31f97cdcc628a

提示:master节点的cup数量要大于等于2,否则会报如下错误:

[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2

解决方法如下:

//方法一
修改master节点的cup数量要大于等于2

//方法二
添加 --ignore-preflight-errors=NumCPU 忽略运行时CPU错误

kubeadm init \
--apiserver-advertise-address=192.168.198.145 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.23.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--ignore-preflight-errors=NumCPU


提示:
如果出现ERROR Swap错误,同样可以在后面添加 --ignore-preflight-errors=Swap 忽略运行时Swap错误

2.2、配置kubectl工具
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config



2.3、安装Calico网络插件

这里安装方式为:使用Kubernetes API 数据存储安装 Calico,50 个节点或更少

2.3.1、下载calico.yaml配置文件
curl https://docs.projectcalico.org/manifests/calico.yaml -O


如果上面的calico.yaml文件下载不了,可以下载我提供的calico.yaml文件:https://pan.baidu.com/s/1pAKnnACzAotysMRwVUgyBA 提取码:8mvw


2.3.2、修改calico.yaml配置文件

由于calico.yaml配置文件中使用的pod cidr地址段默认为192.168.0.0/16,与我们在kubeadm init初始化master节点时,指定的–pod-network-cidr地址段10.244.0.0/16不同,所以需要修改calico配置文件,取消CALICO_IPV4POOL_CIDR变量和value前的注释,并将value值设置为与--pod-network-cidr指定地址段相同的值,即:10.244.0.0/16

//1、修改calico.yaml配置文件
vim calico.yaml

//2、取消前面的注释,将value值改为 10.244.0.0/16
- name: CALICO_IPV4POOL_CIDR
  value: "10.244.0.0/16"



2.3.2、应用calico网络
kubectl apply -f calico.yaml



3、部署Kubernetes Node节点 (在node节点上执行)

3.1、加入Kubernetes集群
kubeadm join 192.168.198.145:6443 --token tgmuix.lj2v3b6ogev7yjp6 \
    --discovery-token-ca-cert-hash sha256:2328518d9636ebbe4cdc05f1750e2e89071ef7ed98561f16a1b31f97cdcc628a

当看到如下输入信息时,则表示加入Kubernetes集群成功

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run ‘kubectl get nodes’ on the control-plane to see this node join the cluster.


提示:如果加入失败,可以使用kubeadm reset命令进行清理,然后再重新加入


4、集群状态监测与ipvs的开启 (在master节点上执行)

4.1、查看集群状态
kubectl get componentstatus


4.2、查看集群各个节点
kubectl get nodes


可以看到此时,node节点还处在NotReady状态 (这是由于启动pod需要时间,多等待一段时间即可)


4.3、查看所有pod是否已经启动成功
kubectl get pods -n kube-system

可以看到有一个名为calico-node-nmbrg的pod处于Init状态 (提示:其实等待一段时间就好了)


我们可以通过kubectl describe pod calico-node-nmbrg -n kube-system命令查看其详情,可以看到upgrade-ipam容器已经成功启动


4.4、再次查看集群各个节点状态 和 所有pod状态 (请务必确保所有pod都处于Running状态)
//1、查看节点状态
kubectl get nodes

//2、查看pod状态
kubectl get pods -n kube-system



4.5、配置kubectl命令自动补全功能
//1、安装epel-release 和 bash-completion
yum install -y epel-release bash-completion

//2、配置kubectl命令自动补全
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

//3、测试配置是否成功
kubectl tab键




4.6、配置kube-proxy开启ipvs
4.6.1、编辑资源类型为configmap的kube-proxy

提示:资源类型为configmap 可以简写成 cm

//1、编辑kube-proxy
kubectl edit cm kube-proxy -n kube-system

//2、修改mode
mode: ""   修改为  mode: "ipvs"



4.6.2、删除之前运行的资源类型为pod的kube-proxy
kubectl get pod -n kube-system |grep kube-proxy |awk '{system("kubectl delete pod "$1" -n kube-system")}'



4.6.3、查看新的资源类型为pod的kube-proxy是否启动

提示:如果执行如下命令,没有结果输出,请耐心等待一段时间,再执行如下命令,启动pod也是需要花一段时间的

kubectl get pods -n kube-system | grep kube-proxy



4.6.4、查看kube-proxy是否开启ipvs
ipvsadm -Ln

kube-proxy未开启ipvs前的输出结果:


kube-proxy开启ipvs后的输出结果:


4.7、测试DNS是否可用
4.7.1、查看资源类型为svc的kubernetes的ClusterIP地址

提示:资源类型为service 可以简写成 svc

kubectl get svc



4.7.2、查看Node节点是否有污点

Kubernetes 1.6 已经支持(alpha阶段)节点问题的表示。换句话说,当某种条件为真时,node controller会自动给节点添加一个 taint(污点),Taints(污点) and Tolerations(容忍) - Kubernetes文档

//查看污点标记
kubectl get no -o yaml | grep taint -A 5


可以看到只有Master节点被打上了NoSchedule无法调度的污点

4.7.3、测试DNS 通过资源类型名称解析其ClusterIP地址
//1、拉取radial/busyboxplus镜像
docker pull radial/busyboxplus

//2、创建deployment类型资源 (deployment控制器会启动pod)
kubectl run -it busyboxplus --image=radial/busyboxplus

//3、解析其ClusterIP
nslookup kubernetes



可以看到kubernetes解析的ClusterIP地址为10.96.0.1,与我们之前查看资源类型为svc的kubernetes的ClusterIP地址一致,同时还能看到kube-dns对应的ClusterIP地址为10.96.0.10



5、安装镜像仓库

由于HarBor镜像仓库需要更多的资源,所以这里我选择是Registry镜像仓库

registry镜像仓库的搭建:https://blog.csdn.net/qq_39135287/article/details/103307664

如果Master节点服务器配置比较高 或者 电脑配置比较高可以虚拟出多台虚拟机的话,可以尝试搭建 企业级容器镜像仓库HarBor:https://blog.csdn.net/qq_39135287/article/details/104041772

由于我的电脑配置低,虚拟一台虚拟机安装HarBor镜像仓库会导致电脑运行很卡,所以这里我直接选择在Master节点上安装registry镜像仓库

提示:安装好镜像仓库后,不要忘了在所有节点(包括master节点)daemon.json配置文件中,添加镜像仓库的地址,让docker信任私有仓库地址


6、常见问题

6.1、忘记token或者token失效,后续节点如何重新加入集群
6.1.1、生成新的token并查看token
//方式一:生成永久token,--ttl 0:表示设置永不过期 (不安全,不推荐)
kubeadm token create --ttl 0

//方式二:生成临时token,有效期为一天 (可以保证集群安全性,推荐)
kubeadm token create

//查看生成的token
kubeadm token list



6.1.2、获取ca证书的sha256编码hash值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'


6.1.3、组装生成有效的 kubeadm join命令

通过新生成的 token 和 ca证书sha256编码的hash值 重新组装得到有效的 kubeadm join命令

kubeadm join 192.168.198.145:6443 --token gzxm5g.z2n80zos0ior1ln8 \
    --discovery-token-ca-cert-hash sha256:9a39cca67b506c8c7b4e59bc9e8e934b1c779342ed159f2318ce9ca2533cf58f

6.2、如果master节点安装过程失败,重置kubeadm
kubeadm reset
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1
rm -rf /var/lib/cni/


Kubernetes入门到实践系列文章列表:

Kubernetes入门到实践 (一) Kubernetes介绍 与 yum安装Kubernetes集群
Kubernetes入门到实践 (二) Kubeadm安装Kubernetes集群




  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值