CentOS 7.6 使用 kubeadm 部署 v1.16集群

部署 Kubernetes 集群

Kubernetes 集群部署的方式有很多选择,简单的可以基于 kubeadm 一类的部署工具运行几条命令即可实现,而复杂的则可以使从零开始手动构建集群环境。

kuberadm 部署工具

kubeadm 是 Kubernetes 项目自带的集群构建工具,它负责构建一个最小化的集群以及将其启动等必要的基本步骤,简单来讲,kubeadm 是 Kubernetes 集群全生命周期的管理工具,可用于实现集群的部署、升级/降级及拆除。在部署操作中,kubeadm 尽关心如何初始化并启动集群,余下的其他操作,例如安装 Kubernetes Dashboard、监控系统、日志系统等必要的附加组件则不再其考虑范围之内,需要自行部署。

kubeadm 集成了以下工具程序:
kubeadm init 工具用于集群初始化,其核心功能是部署 Master 节点的各个组件。
kubeadm join 工具用于将Node节点加入到指定集群中。
kubeadm token 可于集群构建后管理用于加入集群时使用的认证临牌 (token)。
kubeadm reset 命令的功能则是删除集群构建过程中生成的文件以重置回初始状态。

kubeadm 还支持管理初始引导认证令牌 (Bootstrap Token),完成待加入的新节点首次联系 API Server 时的身份认证(基于共享密钥)。另外,他们还支持管理集群版本的升降级操作。

集群运行模式

Kubernetes 集群支持三种运行模式:
1)独立组件模式:系统各个组件直接以守护进程的方式运行于节点智商,各组件之间相互协作构成集群。
2)静态 Pod 模式:除 kubelet 和 Docker 之外的其他组件 (如 etcd、kube-apiserver、kube-controller-mangeer和 kube-scheduler等)都是以静态 Pod 对象运行于 Master 主机之上。
3)自托管模式:这种模式是 Kubernetes的 自托管模式(self-hosted),它类似于第二种方式,将除了 kubelet 和 Docker 之外的其他组件运行为集群之上的 Pod 对象,但不同的是,这些 Pod 对象托管运行在 Kubernetes 集群自身之上受控于 DaemonSet 类型的控制器。而非静态的 Pod 对象。

使用 kubeadm 部署的 Kubernetes 集群可运行为第二种或者第三种模式,默认为静态 Pod 对象模式,需要使用自托管模式时,kubeadm init 命令使用 “--features-gates=selfHosting“,选项即可,第一种模式集群的构建需要将各组件运行于系统之上的独立守护进程中,期间需要用到的证书及 Token 等认证信息也需要手动生成,过程繁琐且极易出错;若有必要用到,则建议使用 GitHub 上的项目辅助进行。

准备集群环境

如下图所示,该集群由一个 Master 主机和三个 Node 主机组成,基于 kubeadm 部署,除了kubelet 和 Docker 之外的其他集群组件都运行于 Pod 对象中。

角色 IP地址 主机名 系统版本 内核版本 docker版本 k8s版本
master 192.168.31.245 kube-master CentOS 7.6.1810 3.10.0-957.el7.x86_64 18.09.9 v1.16.0
node 192.168.31.241 kube-node1 CentOS 7.6.1810 3.10.0-957.el7.x86_64 18.09.9 v1.16.0
node 192.168.31.242 kube-node2 CentOS 7.6.1810 3.10.0-957.el7.x86_64 18.09.9 v1.16.0
node 192.168.31.243 kube-node3 CentOS 7.6.1810 3.10.0-957.el7.x86_64 18.09.9 v1.16.0

设置部署Kubernetes必要条件

所有机器操作
安装Kubernetes至少需要2c/2ram以上
1.)关闭防火墙

systemctl stop firewalld && systemctl disable firewalld 

2.关闭SELinux

setenforce 0
sed -i 's/SELINUX=permissive/SELINUX=disabled/' /etc/sysconfig/selinux
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

3.时钟校对

yum install ntpdate.x86_64 -y
timedatectl set-timezone Asia/Shanghai
/sbin/ntpdate ntp2.aliyun.com;/sbin/hwclock -w
cat >> /var/spool/cron/root << EOF
#Clock synchronization
00 00 * * * /sbin/ntpdate ntp2.aliyun.com;/sbin/hwclock -w
EOF

4.修改内核参数

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
modprobe br_netfilter
sysctl --system

5.Swap交换分区
kubernetes自1.8版本起强制要求关闭系统上的交换分区(swap),否则无法启动,如果系统不足或者有其它重要进程使用交换分区时那么也是可以保留交换分区。

1)如果你要禁用交换分区

swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab

2)如果你要启用交换分区

创建交换区原则:
1.创建的swap交换区大小应该大于实际物理内存的容量大小,但是不要过大,以免造成硬盘空间浪费。
2.如果内存IO请求频繁,而单一swap交换区IO队列等待时间过长的话,可以多创建几个swap交换区。
3.原则上优先在IO速度最快的设备上创建。

#创建swap交换分区
#通常创建物理内存2~2.5倍大小的文件作为交换区。
dd if=/dev/zero of=/swap bs=1G count=8

#使用mkswap格式化文件为swap文件系统
#-f 使用文件作为swap交换区
mkswap -f /swap

#启用刚才创建的Swap文件
swapon /swap

#如果有必要可以设置开机自动启用swap文件交换区,修改/etc/fstab,增加一行
echo '/swap swap swap defaults 0 0' >> /etc/fstab

6.安装docker

yum install yum-utils device-mapper-persistent-data lvm2 -y
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce-18.09.9-3.el7 -y
systemctl enable docker && systemctl start docker

7.操作完成后建议重启下机器

reboot

master安装 kubeadm kubelet kubectl

master操作
由于官方Kubernetes镜像源在google,因各种不可描述原因,这里使用阿里云yum源

1.添加阿里云yum源

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

2.安装kubeadm、kubectl、kubelet

yum clean all && yum makecache

#列出目前1.16的所有衍生版本
[root@kube-master src]# yum list kubectl --showduplicates | sort -r | grep 1.16
kubectl.x86_64                       1.16.3-0                         kubernetes
kubectl.x86_64                       1.16.2-0                         kubernetes
kubectl.x86_64                       1.16.1-0                         kubernetes
kubectl.x86_64                       1.16.0-0                         kubernetes
[root@kube-master src]# yum list kubeadm --showduplicates | sort -r | grep 1.16
kubeadm.x86_64                       1.16.3-0                         kubernetes
kubeadm.x86_64                       1.16.2-0                         kubernetes
kubeadm.x86_64                       1.16.1-0                         kubernetes
kubeadm.x86_64                       1.16.0-0                         kubernetes
[root@kube-master src]# yum list kubelet --showduplicates | sort -r | grep 1.16
kubelet.x86_64                       1.16.3-0                         kubernetes
kubelet.x86_64                       1.16.2-0                         kubernetes
kubelet.x86_64                       1.16.1-0                         kubernetes
kubelet.x86_64                       1.16.0-0                         kubernetes

#指定1.16.0版本进行安装
yum install kubectl-1.16.0-0 kubeadm-1.16.0-0 kubelet-1.16.0-0 -y

3.查看kubelet安装了哪些文件

[root@kube-master src]# rpm -ql kubelet 
/etc/kubernetes/manifests
/etc/sysconfig/kubelet
/usr/bin/kubelet
/usr/lib/systemd/system/kubelet.service

[root@kube-master src]# rpm -ql kubeadm
/usr/bin/kubeadm
/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

[root@kube-master src]# rpm -ql kubectl
/usr/bin/kubectl

4.配置kubelet(开启swap分区操作)
如果你禁用了swap分区,那么这步骤直接略过即可,如果开启了swap分区,那么需操作以下来对Kubernetes忽略禁用swap限制

cat <<EOF > /etc/sysconfig/kubelet 
KUBELET_EXTRA_ARGS="--fail-swap-on=false"
EOF

5.设置kubelet服务*
配置文件修改完成后,需要设定kuberlet服务开机自动启动,这也是Kubeadm的强制要求

systemctl enable kubelet

node安装 kubeadm kubelet kubectl

node操作
1.添加阿里云yum源

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

2.安装kubeadm、kubectl、kubelet

yum clean all && yum makecache
yum install kubectl-1.16.0-0 kubeadm-1.16.0-0 kubelet-1.16.0-0 -y

3.配置kubelet(开启swap分区操作)
如果你禁用了swap分区,那么这步骤直接略过即可,如果开启了swap分区,那么需操作以下来对Kubernetes忽略禁用swap限制

cat <<EOF > /etc/sysconfig/kubelet 
KUBELET_EXTRA_ARGS="--fail-swap-on=false"
EOF

4.设置kubelet服务
配置文件修改完成后,需要设定kuberlet服务开机自动启动,这也是Kubeadm的强制要求

systemctl enable kubelet

集群初始化

Master节点操作
Master和各Node的Docker及kubelet配置完成后,便可以在master节点上执行 “kubeadm init”命令进行集群初始化。
初始化过程中 Kubernetes会下载管理节点所用到的 6 个 docker镜像分别为 Kubernetes 的各个组件,以 静态 Pod 的方式运行于容器之中。
kubeadm init命令支持两种初始化方式:
1)通过命令行选项传递关键的参数设定
2)基于 yaml 格式的专用配置文件设定更详细的配置参数
这里演示通过第一种方法进行初始化。

1.Master 初始化

[root@kube-master src]# kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.16.0 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--apiserver-advertise-address=0.0.0.0 \
--ignore-preflight-errors=Swap \
--token-ttl 30m

参数解释:

  • --image-repository:初始化过程中会去docker仓库拉去镜像,默认指定的为docker hub,所以在此使用–image-repository参数指定阿里云镜像。
  • --kubernetes-version:指定正在使用的 Kubernetes 程序组件的版本号,需要与 kubelet 的版本号相同。
  • --pod-network-cidr:Pod 网络的地址范围,其值为 CIDR 格式的网络地址,使用 flannel 网络插件时,其默认地址为 10.244.0.0/16
  • --service-cidr:Service 的网络地址范围,其值为 CIDR 格式的网络地址,默认地址为 10.96.0.0/12
  • --apiserver-advertise-address:API Server 通告给其它组件的IP地址,一般为 Master 节点的IP地址,0.0.0.0 标识节点上所有可用的地址。
  • ignore-preflight-errors:忽略哪些运行时的错误信息,其值为 Swap 时,表示忽略因 swap 未关闭而导致的错误。
  • --token-ttl:token令牌自动删除时间,默认为24小时,指定为 0 表示永不过期,指定单位可以使 秒s 分m 时h,在node加入Kubernetes集群时需要指定token。

初始化过程中到 kubeadm config images pull 会稍有卡顿

2.初始化完成返回如下

3.设定 kubectl 配置文件
kubectl 是执行 kubernetes 集群管理的核心工具。默认情况下,kubectl会从当前用户主目录(保存于环境变量HOME中的值)中隐藏目录 .kube 下名为 config 的配置文件中读取配置信息,包括要接入 Kubernetes 集群、以及用于集群认证的证书或令牌等信息,集群初始化时,kubeadm 会自动生成一个用于此类功能的配置文件 /etc/kubernetes/admin.conf,将它复制为用户的 $HOME/.kube.config即可直接使用。
直接复制以上绿色框画中的命令即可

[root@kube-master src]# mkdir -p $HOME/.kube
[root@kube-master src]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@kube-master src]# sudo chown $(id -u):$(id -g) $HOME/.kube/config

目前,一个 Kubernetes Master 节点已经配置完成。
使用 kubectl get nodes可以获取到集群节点相关状态信息,如果命令结果Master节点状态为 “NotReady(未就绪)”,这是因为集群中尚未安装网络插件所致,网络插件安装完成后即为 “Ready(就绪)” 状态。

[root@kube-master src]# kubectl get nodes
NAME          STATUS     ROLES    AGE     VERSION
kube-master   NotReady   master   9m23s   v1.16.0

如果你的配置或输出结果有误,则可以通过 kubeadm reset 命令重新进行集群初始化

部署网络插件

Master操作
为 Kubernetes 提供 Pod 网络插件的有很多,目前最流行的是 flannelCalico。相比较来说,flannel 以其简单、易部署、易用性广受欢迎。
基于 kubeadm 部署时,flannel 同样运行为 Kubernetes 集群的附件,以 Pod 的形式部署运行于每个集群节点上以接受 Kubernetes 集群管理。部署方式可以获取其资源清单于本地而后部署集群中,也可以直接在线进行应用部署。部署命令是 kubectl applykubectl create

1.flannel 网络插件部署

[root@kube-master src]# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

手动下载kube-flannel.yml文件后,修改其地址quay.ioquay-mirror.qiniu.com,因quay.io为国外地址,国内访问超级慢,如果你没有正确的上网,那么必定拉不下 flannel镜像,所以这里把 quay.io 改为国内地址 quay-mirror.qiniu.com

[root@kube-master src]# sed -i 's/quay.io/quay-mirror.qiniu.com/g' kube-flannel.yml
[root@kube-master src]# kubectl apply -f kube-flannel.yml
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds-amd64 created
daemonset.apps/kube-flannel-ds-arm64 created
daemonset.apps/kube-flannel-ds-arm created
daemonset.apps/kube-flannel-ds-ppc64le created
daemonset.apps/kube-flannel-ds-s390x created

配置 flannel 网络插件时,Master 节点上的 Docker 首先会去获取 flannel 的镜像文件,而后根据镜像文件启动相应的 Pod 对象。待其运行完成后再次检查集群中的节点状态可以看出 Master 已经变为 “Ready” 状态。

[root@kube-master src]# kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
kube-master   Ready    master   13m   v1.16.0

如果发现你的 flannel Pod 处于 ImagePullBackOff 状态,那么就是 flannel 镜像未拉取成功,而正常的则为 Running状态

[root@kube-master src]# kubectl get pods -n kube-system | grep flannel
kube-flannel-ds-amd64-wtk6q           1/1     Running   0          3m28s

2.正确上网部署flannel(可选)
如果你可以正确规范上网,则使用以下可直接进行部署

[root@kube-master src]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

3.卸载flannel网络插件(可选)
如果你的网络插件 flannel 拉取失败,或需要重新部署此插件,可以使用 kubectl delete -f $uri 来进行删除此配置

[root@kube-master src]# kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

添加Node到集群

任何一个Node加入集群中的节点都需要先经过 API Server 完成认证,其认证方法和认证信息在 Master 上进行集群初始化的时 kubeadm init 命令执行时输出到了最后一行。
图示:

如果忘记了加入集群的命令,可通过 kubeadm token create --print-join-command命令获取

[root@kube-master src]# kubeadm token create --print-join-command
kubeadm join 192.168.31.245:6443 --token e0vezd.o8s6mopfjibpbpaq     --discovery-token-ca-cert-hash sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2

在Node加入集群时需要加上 --ignore-preflight-errors=Swap 选项来忽略Swap分区警告问题。
提供给 API Server 的 bootstap token 认证完成后,kubeadm join 命令会为后续 Master 与 Node 组件间的双向 ssl/tls 认证生成私钥及证书签署请求,并由 Node 在首次加入集群时提交给 Master 端的 CA 进行签署。默认情况下,kubeadm 配置 kube-apiserver 启用了 bootstrap TLS功能,并支持证书的自动签署。于是,kubelet 及 kube-proxy 等组件的相关私钥和证书文件在命令执行结束后便可自动生成,他们默认莫存储于 /var/lib/kubelet/pki目录中

kube-node1加入集群

[root@kube-node1 ~]# kubeadm join 192.168.31.245:6443 \
--token e0vezd.o8s6mopfjibpbpaq  \
--ignore-preflight-errors=Swap \
--discovery-token-ca-cert-hash \
sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2

kube-node2加入集群

[root@kube-node2 ~]# kubeadm join 192.168.31.245:6443 \
--token e0vezd.o8s6mopfjibpbpaq  \
--ignore-preflight-errors=Swap \
--discovery-token-ca-cert-hash \
sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2

kube-node3加入集群

[root@kube-node3 ~]# kubeadm join 192.168.31.245:6443 \
--token e0vezd.o8s6mopfjibpbpaq  \
--ignore-preflight-errors=Swap \
--discovery-token-ca-cert-hash \
sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2

Master查看集群状态
以下节点状态都为 “Ready” 就绪状态,则证明集群部署成功。当然现在只是最小化部署Kubernetes集群,一个功能完整的 Kubernetes 集群应当具备的附加组件还包括 DashboardIngress ControllerHeapster/Prometheus等。

[root@kube-master src]# kubectl get nodes
NAME          STATUS   ROLES    AGE     VERSION
kube-master   Ready    master   30m     v1.16.0
kube-node1    Ready    <none>   2m32s   v1.16.0
kube-node2    Ready    <none>   89s     v1.16.0
kube-node3    Ready    <none>   86s     v1.16.0

kubeadm init 初始化信息可通过 kubeadm config 命令来进行导出为 yaml 格式的文件

[root@kube-master src]# kubeadm config print init-defaults > kubeadm-init.yaml
[root@kube-master src]# cat kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 1.2.3.4
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: kube-master
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

获取集群状态信息

Kubernetes集群Server端和Client端的版本等信息可以使用 kubectl version 命令进行查看

[root@kube-master src]# kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.0", GitCommit:"2bd9643cee5b3b3a5ecbd3af49d09018f0773c77", GitTreeState:"clean", BuildDate:"2019-09-18T14:36:53Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.0", GitCommit:"2bd9643cee5b3b3a5ecbd3af49d09018f0773c77", GitTreeState:"clean", BuildDate:"2019-09-18T14:27:17Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}

默认输入信息很多,这里可简化只查看版本号

[root@kube-master src]# kubectl version --short=true
Client Version: v1.16.0
Server Version: v1.16.0

Kubernetes的API Server地址,此地址通常被其它程序所调用,查看Kubernetes API Server地址

[root@kube-master src]# kubectl cluster-info
Kubernetes master is running at https://192.168.31.245:6443
KubeDNS is running at https://192.168.31.245:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

也可以使用 kubectl cluster-info dump 来获取 kubernetes 集群的更多信息 metadata元数据

从集群中移除节点

运行过程中,若有节点需要从正常运行的集群中移除,则可使用如下步骤进行。

例如我们将 kube-node2 从 kubernetes 集群中移除,如下:
1.在Master使用 kubectl drain 命令将 kube-node2 上的所有资源迁移至集群中的其它节点

[root@kube-master src]# kubectl drain kube-node2 --delete-local-data --force --ignore-daemonsets
[root@kube-master src]# kubectl get nodes
NAME          STATUS                     ROLES    AGE   VERSION
kube-master   Ready                      master   52m   v1.16.0
kube-node1    Ready                      <none>   24m   v1.16.0
kube-node2    Ready,SchedulingDisabled   <none>   23m   v1.16.0
kube-node3    Ready                      <none>   23m   v1.16.0

2.从 Kubernetes 集群中移除 kube-node2 节点

[root@kube-master src]# kubectl delete node kube-node2
node "kube-node2" deleted
[root@kube-master src]# kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
kube-master   Ready    master   53m   v1.16.0
kube-node1    Ready    <none>   25m   v1.16.0
kube-node3    Ready    <none>   24m   v1.16.0

3.将 kube-node2 重新加入Kubernetes集群

#在Master获取加入集群 token
[root@kube-master src]# kubeadm token create --print-join-command
kubeadm join 192.168.31.245:6443 --token 6fs57x.86ljj77hakrzf9h0     --discovery-token-ca-cert-hash sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2
#在kube-node2上进行加入操作,加入集群前必须先经过重置,因之前有加入集群的信息存在,须先清空
[root@kube-node2 ~]# kubeadm reset
[root@kube-node2 ~]# kubeadm join 192.168.31.245:6443 \
--token e0vezd.o8s6mopfjibpbpaq  \
--ignore-preflight-errors=Swap \
--discovery-token-ca-cert-hash \
sha256:947146190e917a2a06f7319602bd512aab4206cf9a058dca4e66e4aa1ac99ab2

4.在主节点获取节点信息

[root@kube-master src]# kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
kube-master   Ready    master   59m   v1.16.0
kube-node1    Ready    <none>   31m   v1.16.0
kube-node2    Ready    <none>   12s   v1.16.0           #kube-node2已加入
kube-node3    Ready    <none>   29m   v1.16.0

查看 Master与Node 都运行了哪些组件

Master

Nodes







「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论