Kubernetes平台介绍
为什么会出现kubernetes
(1)容器技术(如Docker)在2013年左右开始流行。容器能够轻量化地打包应用程序及其依赖项,保证跨环境的一致性运行。相比传统的虚拟机,容器启动速度快、资源占用小,成为软件开发和部署的理想工具。然而,管理大量容器的复杂性也随之增加,尤其是在生产环境中。企业需要一种能够自动化调度、管理和扩展容器的解决方案。当Docker解决了应用打包的问题后,PaaS上应用大规模部署与管理的问题愈发突出。此时,业内明白:容器本身没有“价值”,有价值的是容器编排。容器编排对Docker及容器进行更高级更灵活的管理,按照用户的意愿和整个系统的规则,完全自动化的处理好容器之间的各种关系。容器技术做为底层基础技术,只能用来创建和启动容器的小工具,用户最终部署的还是他们的网站、服务、数据库,甚至是云计算业务。这就需要一个真正的PaaS平台,让用户把自己的容器应用部署在此之上。
(2)传统的单体架构难以适应复杂、快速变化的业务需求,微服务架构因此变得流行。微服务架构将应用程序拆分为多个独立的服务,每个服务可以独立开发、部署和扩展。容器技术非常适合微服务的部署需求,但随着服务数量的增加,如何协调、监控和管理多个微服务实例变得非常具有挑战性。
(3)在大规模容器化环境中,手动管理和运维工作非常复杂且容易出错。例如:
应用需要运行在数百甚至数千个容器上,如何保证资源的合理分配和利用?当某个容器或服务失效时,如何自动恢复服务?如何确保在更新应用时不中断现有服务? 传统的手工方式已经无法高效解决这些问题,因此自动化容器编排工具成为必需。
(4)随着云计算的广泛应用,特别是混合云和多云架构的普及,企业希望其应用能够灵活地在不同的云平台或本地数据中心运行。而容器本身提供了跨平台的一致性运行环境,但跨云管理容器化应用仍然是个难题。
Kubernetes介绍
Kubernetes(简称K8s)是一个开源的容器编排平台,Kubernetes源于希腊语,意为“舵手”。
主要用于自动化应用程序的部署、扩展和管理。它最早由Google开发,并于2014年捐赠给云原生计算基金会(CNCF)。Kubernetes旨在帮助开发人员和运维团队有效地管理容器化应用,尤其是在生产环境中的大规模集群下。它在微服务架构、容器化应用和云原生应用开发中广泛应用。Kubernetes的基础特性是 Google 公司在容器化基础设施领域多年来实践经验的沉淀与升华。这个实践与升华的过程,就是Kubernetes的前身:Borg系统。Borg系统一直以来都被誉为Google内部最强大的“秘密武器”,是Google整个基础设施的核心依赖。很多应用框架已经运行在Borg上多年,其中包括了内部的MapReduce、GFS、BigTable、Megastore等,上层应用程序更是有这些耳熟能详的产品:Gmail、Google Docs、Google Search等。
关于 Kubernetes,应该了解的第一件事是,它是一个分布式系统。即它有多个组件分布在网络上的不同服务器上。这些服务器可以是虚拟机或裸机服务器,称之为 Kubernetes 集群。
主要功能
自我修复:一旦某一个容器崩溃,能够在短时间内迅速启动新的容器
弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
服务发现:服务可以通过自动发现的形式找到它所依赖的服务
负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
存储编排:可以根据容器自身的需求自动创建存储卷
Kubernetes优势
Kubernetes的优势在于其自动化能力、弹性和高可用性,同时还能提供强大的扩展性和平台无关性。无论是小规模的开发环境还是大规模的生产集群,Kubernetes都能够高效管理容器化应用,帮助企业实现更快的部署周期、更稳定的服务和更高效的资源利用。具体讲述:
(1)自动化容器编排与调度:
Kubernetes自动化了容器的调度和管理工作。它根据集群中各节点的资源利用率、负载情况和策略(如优先级、亲和性等),自动选择最佳节点来部署应用容器。这减少了手动操作和人为错误,使资源使用更高效。
(2)故障自动恢复:
Kubernetes具有自愈功能,能够在应用实例出现故障时,自动重启或替换有问题的Pod,确保服务的持续可用性。
节点崩溃时,Kubernetes会重新调度相关的Pod到健康的节点上。
Pod故障时,会自动重启或替换。
如果应用健康检查失败,它还会根据预定义规则启动修复操作。
(3)可扩展性与弹性:
Kubernetes支持水平扩展,即根据应用的负载情况自动扩展或缩减Pod的数量。当应用流量增加时,Kubernetes可以根据指标(如CPU和内存使用率)自动扩容Pod实例;当负载减少时,则自动缩容,从而提高资源利用率,节省成本。
(5)服务发现与负载均衡:
Kubernetes提供了内置的服务发现和负载均衡功能。每个Pod在启动时都会被分配一个独立的IP地址,Kubernetes可以通过Service资源提供稳定的访问入口。即使Pod的IP地址发生变化,服务的访问地址也不会变动。
(6)跨平台和云无关性
Kubernetes支持在各种环境中运行,包括本地数据中心、私有云、公有云以及混合云架构。它可以让开发者和运维人员将应用无缝迁移到不同的平台上,减少对单一云平台的依赖,提供更大的灵活性。
(7)存储编排
Kubernetes可以自动挂载各种类型的存储,包括本地存储、网络文件系统、云存储等。它支持动态和静态持久化存储卷的管理,解决了容器中持久数据存储的问题。
这种存储编排功能使得Kubernetes在处理有状态应用(如数据库、缓存系统)时,也能高效管理存储资源。
(8) 可观察性和监控:
Kubernetes为集群和应用的监控提供了良好的支持。它通过Metrics API、日志聚合工具,与Prometheus、Grafana等监控系统轻松集成,提供实时监控、日志分析和性能跟踪。Kubernetes的这种可观察性能力让运维人员能够迅速发现问题,优化应用和集群性能。
Kubernetes支持密钥管理、加密存储和Pod安全策略,确保集群中的数据和应用安全。
Kubernetes架构
Kubernetes的架构设计是为了提供一个高度自动化、可扩展和可管理的容器编排平台。它通过控制平面管理集群的全局状态,并通过工作节点执行具体的应用部署。各个组件协同工作,使得Kubernetes能够管理数百甚至数千个容器实例;Kubernetes架构图:
控制平面组件:
kube-api服务器,etcd,kube-调度程序,kube-控制器管理器,云控制器管理器。
工作节点组件:
Kubelet,kube-代理,容器运行时。
控制平面组件:【老板】
(1)API Server
作用:API Server是Kubernetes的前端接口,负责处理所有的API请求(如创建、更新、删除资源)。所有外部用户或内部组件都通过API Server与集群交互,协调控制平面和工作节点组件之间的所有进程。
功能:接收命令和配置请求(如kubectl命令),并将这些请求存储在etcd中或分发给其他组件执行,且它是唯一与etcd通信的组件。它是集群的核心入口点,提供集群的CRUD操作。
(2)etcd(分布式存储)
作用:etcd 是一个开源的强一致性分布式键值存储是Kubernetes的一致性和可靠性存储系统,用于保存整个集群的配置数据、状态和元数据。
功能:存储Kubernetes集群的所有对象状态(如Pod的定义、部署信息等),是集群的“源真相”。etcd 被设计为在不牺牲一致性的情况下作为集群在多个节点上运行。作为一个分布式键值存储,确保数据的高可用性和一致性。
(3)Scheduler(调度器)
作用:调度器负责为新创建的Pod选择合适的工作节点运行。它根据集群的资源使用情况和策略进行调度(指定容器要求)。
功能:当Pod创建时,它需要被分配到某个节点。调度器会考虑节点的资源(CPU、内存)、节点标签、节点状态等因素,并决定在哪个节点上启动Pod。调度策略可以自定义,确保应用的高效分布和资源利用率。
调度原理:
调度器会持续监控集群中未被调度的 Pod,当发现一个新创建的 Pod 处于 Pending 状态时,它会开始为这个 Pod 选择一个合适的节点。Pod 的定义中通常包含了资源需求、亲和性和反亲和性等调度规则。调度器首先会根据 硬性条件 对集群中的节点进行筛选,排除不符合条件的节点。这些硬性条件包括:
节点必须有足够的 CPU、内存等资源来满足 Pod 的需求。如果 Pod 规定了要调度到特定标签的节点,调度器会筛选出带有这些标签的节点。调度器会根据这些过滤条件,将不符合要求的节点排除,最终得到一个“候选节点列表”。
过滤后,调度器会对剩下的候选节点进行评分。评分的目的是从符合条件的节点中选出“最优节点”。 在打分结束后,调度器会选择得分最高的节点作为最终的调度目标,并将 Pod 分配到该节点上。 调度结果会通过 Kubernetes API 提交给 API Server,然后该节点上的 Kubelet 会接收任务并启动对应的容器。最后,调度器通过 Kubernetes 的 bind API 将 Pod 绑定到选择的节点上。此时,Pod 的状态会从 Pending 变为 Running,并开始在该节点上启动对应的容器。
(4)Controller Manager(控制器管理器)
作用:Controller Manager是集群内多个控制器的集合,每个控制器都负责维护集群中某些资源的期望状态与实际状态一致。
ReplicationController:确保指定数量的Pod副本运行。
Node Controller:监控节点的健康状态,发现节点故障时移除不健康节点上的Pod。
Endpoint Controller:负责更新服务与Pod之间的映射关系。
Service Account & Token Controller:创建默认的账号和访问权限。
控制器负责自动化操作,如应用恢复、扩展和滚动更新。
工作节点组件:【打工人】
(1)Kubelet
Kubelet 也是一个控制器,运行在每个工作节点上的核心代理,负责管理该节点上所有的Pod和容器,它监视 Pod 的变化,并利用节点的容器运行时来拉取镜像、运行容器等。
功能:通过与API Server交互,接收调度的Pod信息,确保容器按照预期运行。定期向API Server汇报Pod和节点的状态。执行健康检查,确保Pod处于健康状态。
Kubelet是工作节点上与控制平面交互的主要代理,直接与容器运行时交互(如Docker或containerd)来管理容器。
(2)Kube-Proxy(代理)
Kube-proxy 是一个守护进程,它作为守护进程集在每个节点上运行。Kubernetes 中的服务是一种在内部或向外部流量公开一组 Pod 的方法。创建服务对象时,它会为其分配一个虚拟 IP,被称为 clusterIP。它只能在 Kubernetes 集群中访问。它是一个代理组件,用于实现 Pod 的 Kubernetes 服务概念。Kube 代理与 API 服务器通信,以获取有关服务 (ClusterIP) 和相应 Pod IP 和端口(端点)的详细信息。它还监视服务和终结点的更改。然后,kube-proxy 使用以下任一模式创建/更新规则,将流量路由到 Service 后面的 Pod。
功能:
维护集群内部服务的虚拟IP地址,并将流量代理到实际的Pod上。
实现服务的负载均衡,确保多个Pod实例之间的流量分发。
管理网络规则,确保Pod间通信的正确性。
Kube-Proxy实现了Kubernetes的网络模型,使得Pod之间可以跨节点通信,并为服务提供稳定的访问入口。
(3)容器运行时(Container Runtime)
作用:容器运行时是负责拉取镜像、启动和管理容器的组件。
功能:Kubelet通过与容器运行时(如Docker、containerd、CRI-O等)交互,启动和停止容器。容器运行时支持容器的创建、运行和删除等生命周期管理。
核心资源
(1)容器:kubernetes通过容器技术将应用程序及其依赖进行打包,保证了跨平台的一致性运行。
(2)集群:kubernetes的运行环境一般由多个及其组成,分为主节点(master node)和工作节点(worker node);主节点负责管理集群的控制平面,工作节点负责实际运行容器化的应用
(3)Pod:Kubernetes中的最小部署单位,一个Pod可以包含一个或多个紧密相关的容器。这些容器共享同一个网络和存储空间,通常会一起运行和管理。
(4)Service:是一种抽象的概念,用于定义一组Pod的访问方式和网络连接。Service为Pod提供了一个稳定的网络地址和DNS名称,使得其他应用程序可以通过该地址和名称与Pod进行通信。Kubernetes中的服务用于暴露应用,使得Pod之间或Pod与外部通信能够稳定进行。即使Pod被销毁或重新创建,Service仍然提供稳定的访问地址。
(5)Deployment:用于定义应用程序的期望状态,并确保该状态得到维持。Deployment支持滚动更新和回滚操作,可以方便地进行应用程序的发布和更新。Deployment控制器负责声明和管理Pod的生命周期,保证在集群中正确数量的Pod副本运行。如果某个Pod出问题,Kubernetes会自动重启或替换。
(6)Namespace:Namespace(命名空间),用于在集群中创建虚拟的工作环境,将资源进行隔离和分类。它可以帮助不同的团队或项目在同一个集群中共享资源,同时保持彼此之间的隔离。
(7)节点(Node):集群中的每个物理机或虚拟机称为节点。每个工作节点运行Pod,并由Kubernetes控制。
(8)Replication Controller(副本控制器):Replication Controller用于确保Pod的副本数量与期望的副本数量保持一致。它会监控Pod的状态,并在需要时创建、删除或重新调度Pod,以满足用户定义的副本数量。
Kubernetes工作流程
节点设置(Master 和 Node)定义master节点和node节点。用户通过 YAML文件定义 Kubernetes 资源(如 Pod、Service、Deployment 等)。这些文件通过 kubectl 命令与 API Server 交互,向集群提交资源定义。API Server 是 Kubernetes 集群的入口,负责验证和处理来自 kubectl 或其他应用的请求。API Server 处理后,将资源状态保存在 etcd 中,作为集群的配置状态。Scheduler 根据集群中可用资源、节点状态和调度策略,决定将新创建的 Pod 分配到哪个节点运行。调度器考虑 CPU、内存、拓扑等因素。调度完成后,目标节点上的 Kubelet 接收到调度的 Pod 定义,负责在节点上创建和管理 Pod。Kubelet 会调用容器运行时(如 Docker 或 containerd)启动容器。Service 是 Kubernetes 中的抽象层,定义了一组 Pods 的访问方式,通常是通过 ClusterIP、NodePort 或 LoadBalancer。
Kubernetes 使用 kube-proxy 管理网络规则,保证集群内外的服务请求能够正确地路由到相关 Pod。Service 负责在不同 Pod 之间负载均衡,确保服务的高可用性。
Horizontal Pod Autoscaler(HPA) 可以根据资源使用(如 CPU、内存)动态地增加或减少 Pod 的数量,实现自动扩展。
Kubernetes平台的部署
节点准备
Master | 192.168.128.140 | docker,kubectl,kubeadm,kubelet |
Node1 | 192.168.128.141 | docker,kubectl,kubeadm,kubelet |
Node2 | 192.168.128.142 | docker,kubectl,kubeadm,kubelet |
1.前期准备工作
所有节点均设置
(1)更改主机名
[root@localhost ~]# hostnamectl set-hostname master [root@localhost ~]# hostnamectl set-hostname node1 [root@localhost ~]# hostnamectl set-hostname node2 |
(2)添加映射文件
[root@node1 ~]# cat /etc/hosts 192.168.128.140 master 192.168.128.141 node1 192.168.128.142 node2 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 [root@node1 ~]# |
(3)关闭防火墙
[root@node1 ~]# systemctl stop firewalld;systemctl disable firewalld;setenforce 0 并修改selinux的配置文件,更改为disabled |
(4)设置时间同步
[root@node1 ~]# systemctl start chronyd |
(5)禁用swap分区
swap分区指的是虚拟内存分区,它的作用是物理内存使用完,之后将磁盘空间虚拟成内存来使用,启用swap设备会对系统的性能产生非常负面的影响,所以kubernetes要求每个节点都要禁用swap设备
[root@node1 ~]# vi /etc/fstab 将这一行注释掉 #/dev/mapper/centos-swap swap swap defaults 0 0 |
(6)修改Linux内核参数
[root@node1 ~]# vi /etc/sysctl.d/kubernetes.conf 编辑文件并添加: net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 保存配置文件后,重新加载配置 [root@node1 ~]#sysctl -p 加载网桥过滤模块 [root@node1 ~]# modprobe br_netfilter 查看后台,网桥过滤模块是否启动成功 [root@node1 ~]# lsmod | grep br_netfilter |
(7)配置ipvs功能
下载ipvsadm软件包
[root@node1 ~]# yum -y install ipvsadm |
添加需要加载的模块写进脚本 [root@node1 ~]# vi /etc/sysconfig/modules/ipvs.modules #!/bin/bash modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack_ipv4 |
赋予脚本文件执行权限 [root@node1 ~]# chmod 755 /etc/sysconfig/modules/ipvs.modules 执行脚本文件 [root@node1 ~]# /bin/bash /etc/sysconfig/modules/ipvs.modules 查看对应的模块是都加载成功 [root@node1 ~]# lsmod | grep -e ip_vs -e nf_conntrack_ipv4 |
(8)重启Linux系统
[root@node1 ~]# reboot |
2.安装Docker
选择使用阿里云的镜像 [root@master ~]# yum -y install wget && wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo 下载过后查看yum源 [root@node1 ~]# yum clean all && yum repolist 安装特定版本的Docker-ce,且必须指定--setopt=obsoletes=0,否则yum会自动将Docker-ce更新为最新版本 [root@node1 ~]# yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y 下载Docker-ce后,创建daemon.json文件 [root@master ~]# mkdir /etc/docker/ [root@master ~]# vi /etc/docker/daemon.json { "registry-mirrors": [ "https://do.nark.eu.org", "https://dc.j8.work", "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.mirrors.ustc.edu.cn", "https://docker.nju.edu.cn" ] } |
启动Docker并设置开机自启 [root@master ~]# systemctl start docker;systemctl enable docker |
3.安装kubernetes组件
添加kubernetes国内的yum源
[root@master ~]# vi /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgchech=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg |
安装kubeadm,kubelet,kubectl
[root@master ~]# yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y 在/etc/sysconfig/kubelet下添加配置: [root@master ~]# vi /etc/sysconfig/kubelet KUBELET_GROUP_ARGS="--cgroup-driver=systemd" KUBE_PROXY_MODE="ipvs" |
设置kubelet开机自启
[root@master ~]# systemctl enable kubelet |
4.准备k8s集群镜像
在安装kubernetes集群之前,需要提前准备好集群所需的镜像,可以通过命令进行查看kubernetes集群所需的镜像:
[root@master ~]# kubeadm config images list |
下载镜像:(由于kubernetes的镜像在国外,因为网络原因无法连接,所以更换一种方式下载镜像:从 阿里云镜像仓库 拉取 Kubernetes 所需的镜像,重新打标签为 Kubernetes 默认使用的镜像标签(k8s.gcr.io),以绕过网络限制,最后删除临时使用的阿里云镜像。)
[root@node2 ~]# images=( kube-apiserver:v1.17.4 kube-controller-manager:v1.17.4 kube-scheduler:v1.17.4 kube-proxy:v1.17.4 pause:3.1 etcd:3.4.3-0 coredns:1.6.5 ) [root@node2 ~]# for imageName in ${images[@]};do docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName; docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName; docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName ; done |
下载完成后使用docker images可以查看镜像:
5.master节点初始化
(所有行为都在master节点上进行)
创建集群:集群api-server的IP指向master
[root@master ~]# kubeadm init \ --kubernetes-version=v1.17.4 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --apiserver-advertise-address=192.168.128.140 |
kubeadm init: 该命令用于初始化 Kubernetes 控制平面节点(即主节点)。它将安装和配置 Kubernetes 集群的基本组件,如 API Server、Controller Manager、Scheduler 等。
--kubernetes-version=v1.17.4: 指定要安装的 Kubernetes 版本,这里选择了 v1.17.4。如果不指定版本,kubeadm 会安装默认的最新稳定版。
--pod-network-cidr=10.244.0.0/16: 为集群中的 Pod 分配的 IP 地址范围(CIDR)。该参数指定了 Pod 网络的 IP 地址段。这里使用了 10.244.0.0/16,这是 Flannel 网络插件的默认 IP 段。如果你使用其他网络插件(如 Calico),可能需要配置不同的 CIDR。
--service-cidr=10.96.0.0/12: 为 Kubernetes 服务分配的 IP 地址范围。服务 IP 是用于服务的虚拟 IP,而不是具体的 Pod IP。该 CIDR 定义了 Kubernetes 集群中的所有服务的 IP 范围。
--apiserver-advertise-address=192.168.128.140: 指定 Kubernetes API Server 广播的 IP 地址。这是主节点的 IP 地址,供工作节点加入集群时访问 API Server 使用
等待加载时间,加载过后出现“Your Kubernetes control-plane has initialized successfully!
”表示初始化成功。
创建必要文件:
[root@master ~]# mkdir -p $HOME/.kube [root@master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config [root@master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config |
6.node节点加入集群
在master初始化集群成功后,会生成一条节点加入集群的命令:
在node节点直接执行该命令即可:
[root@node1 ~]# kubeadm join 192.168.128.140:6443 --token 1bvzjx.xgazn9up0ehxxusv --discovery-token-ca-cert-hash sha256:5a34ccecb2401daa20904544be8293b7b9160dd2e9ec9865a6d1625a60c02993 [root@node2 ~]# kubeadm join 192.168.128.140:6443 --token 1bvzjx.xgazn9up0ehxxusv --discovery-token-ca-cert-hash sha256:5a34ccecb2401daa20904544be8293b7b9160dd2e9ec9865a6d1625a60c02993 |
Node节点加入集群成功。
7.安装网络插件
所有节点下载calico.yaml文件
[root@master ~] curl https://docs.projectcalico.org/archive/v3.17/manifests/calico.yaml -O |
查询calico所需要的所有镜像:
[root@master ~]# grep image calico.yaml |
将查到的所需镜像全部使用docker pull拉取(所有节点上进行)
docker pull docker.io/calico/cni:v3.17.6 docker pull docker.io/calico/pod2daemon-flexvol:v3.17.6 docker pull docker.io/calico/kube-controllers:v3.17.6 docker pull docker.io/calico/node:v3.17.6 |
下载完成后查看
修改calico.yaml 文件,CALICO_IPV4POOL_CIDR的IP段要和kubeadm初始化时候的pod网段一致,注意格式要对齐,不然会报错
在master节点上运行应用calico.yaml文件
[root@master ~]# kubectl apply -f calico.yaml |
查看节点状态:
[root@master ~]# kubectl get nodes |
网络插件安装成功!
测试:
1.部署nginx
[root@master ~]# kubectl create deployment nginx --image=nginx:1.14-alpine |
2.暴露端口
[root@master ~]# kubectl expose deployment nginx --port=80 --type=NodePort |
3.查看服务状态
等待一段时间查看服务状态:
[root@master ~]# kubectl get pods,svc |
4.最后在访问nginx服务
标签:容器,Kubernetes,集群,详细,Pod,root,节点,搭建 From: https://blog.csdn.net/2401_83649605/article/details/142466494