k8s诞生于google,是一个开源的、跨服务器集群容器调度平台,用于管理云平台多个主机上的容器化应用。k8s可以自动化应用容器的部署、扩展和操作。k8s的目标是让部署容器化的应用简单并且高效,其提供了应用部署、规划、更新、维护的机制。k8s与docker的关系就相当于机场与飞机的关系。k8s可以管理着若干个容器。
K8s主体架构
主要核心组件
-
Master组件
Master为集群控制管理节点,负责整个集群的管理和控制。几乎所有的集群控制命令都是在master上面执行的。用户可以部署多个master节点。master节点可以是物理机也可以是虚拟机。-
kube-apiserver
kube-apiserver用于暴露k8s API,提供了资源操作的唯一入口。任何资源请求/调用操作都是通过kube-apiserver提供的接口进行的。提供了k8s各类资源对象的增删改查的HTTP Rest接口,是整个系统的数据总线和数据中心。k8s API服务提供了集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更,提供了其他模块之间的数据交互和通信的枢纽,是资源配额控制的入口,拥有完备的集群安全机制。 -
etcd
etcd是k8s高可用的一致性键值存储系统,也是其提供的默认存储系统,用于存储所有的集群数据以解决分布式系统中数据一致性的问题,使用时需要为etcd数据提供备份计划。 -
kube-scheduler
kube-scheduler 监视新创建没有分配到Node的Pod,为Pod选择一个Node以供其运行。该调度器会根据特定的调度算法把Pod调度到指定的工作节点(Node)上,这个过程也叫做绑定。k8s调度器的输入为需要调度的Pod和可以被调度的节点的信息,输出为调度算法选择的Node节点,并将该Pod绑定到这个节点上。 -
kube-controller-manager
kube-controller-manager运行管理控制器,它们时集群中处理常规任务的后台线程。逻辑上,每个控制器都是一个单独的进程,但为了降低复杂性,它们都被编译成单个二进制文件,并在单进程中运行。
这些控制器包括: -
节点(Node)控制器:负责在节点出现故障时警示和响应。
-
副本(Replication)控制器:负责为系统中的每个副本控制器对象维护正确的Pod数量。
-
端点(Endpoints)控制器:填充Endpoints对象(连接Services&Pods)。
-
Service Account和token控制器:为新的Namespace创建默认账户访问API、访问token。
-
cloud-controller-manager
云控制器管理器负责与底层云提供商的平台交互。云控制器管理器是k8s版本1.6中引入的。
k8s控制管理器作为集群内部的管理控制中心,负责管理集群内的Node(节点)、Pod(副本)、服务端点(Endpoint)、命名空间(Namespace)\服务账号(ServiceAccount)、资源配额(ResourceQuota)。当某个节点意外宕机时,k8s控制管理器会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。
-
-
节点(Node)组件
Node是k8s集群中的工作负载节点,用于被Master分配工作负载(容器)。Node节点才是k8s中承担主要计算功能的工作节点。Node节点可以是一台物理机,也可以是一台虚拟机。
整个k8s集群中的Node节点协同工作,Master会根据实际情况将某些负载分配给各个Node节点。当某个Node节点出现故障时,其他Node节点会替代其功能。Node的组件有:
- kubelet
kubelet是节点代理,会监视已分配给节点的Pod,确保容器在Pod中运行。每个Node节点都会启动kubelet进程,用来处理master节点下发到本节点的任务,管理Pod和其中的容器。kubelet会在API Service上注册节点信息,定期向master节点汇报节点资源的使用情况,并通过cAdvisor监控容器和节点资源。 - kube-proxy
kube-proxy为节点的网络代理,通过在主机上维护网络规则并执行连接转发来实现k8s的服务抽象。会运行在所有的Node节点上,它监听每个节点上k8s API中定义的服务变化情况,并创建路由规则来进行服务负载均衡。 - Container Runtime
容器运行时是负责运行容器的软件。例如:docker。
- kubelet
-
插件
插件是实现集群功能的Pod和服务,扩展了k8s的功能。主要的插件有:- DNS
k8s的集群DNS扩展插件用于支持k8s集群系统中各服务之间的发现和调用。 - Web UI(Dashboard)
Dashboard(仪表盘)是k8s集群基于Web的通用UI,允许用户管理集群以及管理集群中运行的应用程序。 - Container Resource Monitoring(容器资源监测)
Container Resource Monitoring工具提供了UI监测容器、Pods、服务以及整个集群中的数据,用于检查k8s集群中应用程序的性能。 - Cluster-level Logging(集群级日志记录)
Cluster-level Logging提供了容器日志存储,并且提供了搜索/浏览界面。
- DNS
基本概念
初步了解了k8s的主题架构和核心组件,我们还需要进一步了解一些k8s的基本概念。
-
容器组(Pod)
Pod是k8s集群中运行部署应用或服务的最小单元,一个Pod由一个或多个容器组成。在一个Pod中,容器共享网络和存储,并且在一个Node上运行。
K8s为每个Pod都分配了唯一的IP地址,称为Pod IP。一个Pod的多个容器共享Pod IP地址。k8s要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,通常采用虚拟二层网络技术来实现,例如Flannel、Open vSwitch等。因此,在k8s中,一个Pod的容器与另外主机上的Pod容器能够直接通信。
Pod有两种类型:普通的Pod和静态Pod。静态Pod不存放在etcd存储里面,而是存放在某个具体的Node上的一个具体文件中,并且只在Node上启动运行。普通的Pod一旦被创建,就会被存储到etcd中,随后会被k8s master调度到某和具体的Node上并进行绑定,该Node上的kubelet进程会将其实例化成一组相关的容器并启动起来。当Pod的某个容器停止时,k8s会自动检测到这个问题并且重新启动Pod(重启Pod的所有容器);如果Pod所在的Node宕机,就会将这个Node上的所有Pod重新调度到其他节点上运行。
Pod在Node节点上被创建、启动或者销毁。每个Pod中运行着一个特殊的被称为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此它们之间的通信和数据交换更高效,在设计时我们可以充分利用这个特性,将一组密切相关的服务进程放入同一个Pod中。
同一个Pod中的容器之间仅需要通过localhost就能互相通信。同一个Pod中的业务容器共享Pause容器的IP地址,共享Pause容器挂载的存储卷。
Pod是k8s调度的基本工作单元,Master节点会以Pod为单位,将其调度到Node节点上。
-
服务(Service)
在k8s中,Pod会经历“生老病死”而无法复活,也就是说,分配给Pod的IP会随着Pod的销毁而消失,这就会导致一个问题——如果由一组Pod组成一个集群来提供服务,某些Pod提供后端服务API,某些Pod提供前端界面UI,那么该如何保证前端能够稳定地访问这些后端服务呢?这就是Service的由来。
Service在k8s中是一个抽象的概念,定义一组逻辑上的Pod和一个访问它们的策略(通常称为微服务)。这一组Pod能够被Service访问到,通常是通过Label选择器确定的。一个服务可以看作是一组提供相同服务的Pod的对外访问接口。例如,一个图片处理的后端程序,它运行了3个副本,这些副本是可互换的——前端程序不需要关心它们调用了哪个后端副本。虽然组成这一组的后端程序的Pod实际上可能会发生变化,但是前端无须知道。 -
卷(Volume)
和Docker不同,k8s的Volume定义在Pod上,被一个Pod中的多个容器挂载到具体的文件目录上,当容器终止或重启时,Volume中的数据也不会丢失。也就是说,在k8s中,Volume是Pod能够被多个容器访问的共享目录。
目前,k8s支持的卷类型如下所示:
https://kubernetes.feisky.xyz/concepts/objects/volume -
标签(Labels)和标签选择器(Label Selector)
Labels其实就是附加到对象(例如Pod)上的键值对。给某个资源对象定义一个Label,就相当于给它打上了一个标签,随后就可以通过Label Selector来查询和筛选拥有某些Label的资源对象,k8s通过这种方式实现了类似SQL简单又通用的对象查询机制。
总的来说,使用Label可以给对象创建多组标签,Label和Label Selector共同构成了k8s系统中最核心的应用模型,使得被管理对象能够被精细地分组管理,同时实现了整个集群的高可用性。 -
复制控制器(Replication Controller RC)
RC的作用是保障Pod的副本数量在任意时刻都符合某个预期值,不多也不少;如果多了,就杀死几个,如果少了,就创建几个。
RC有点类似于进程管理程序,但是它不是监视单个节点上的各个进程,二十监视多个节点上的多个Pod,确保Pod的数量符合预期值。
当我们定义一个RC并提交到k8s集群后,Master节点上的Controller Manager组件就得到通知,定期巡检系统中当前存活的目标Pod,并确保目标Pod实例的数量刚好等于此RC的期望值。
通过RC,k8s实现了用户应用集群的高可用性,并且大大减少了运维人员在传统IT环境中需要完成的许多手工运维工作(如主机监控脚本、应用监控脚本、故障恢复脚本等)。
常见使用场景:
-
副本集控制器(Replica Set,RS)
RS是下一代复制控制器。RS和RC之间的唯一区别是选择器的支持——RS支持基于集合的Label selector,而RC只支持基于等式的Label selector,所以RS的功能更强大。
RS很少单独使用,主要被Deployment这个更高层的资源对象所使用,从而形成一整套Pod创建、删除、更新的编排机制。 -
部署控制器(Deployment)
Deployment为Pod和Replica Set提供声明式更新。
我们只需要在Deployment中描述想要的目标状态是什么,Deployment controller就会帮我们将Pod和Replica Set的实际状态改变到目标状态。我们可以定义一个全新的Deployment,也可以创建一个新的替换旧的Deployment。
Deployment相对于RC的最大区别是我们可以随时知道当前Pod“部署”的进度。一个Pod的创建、调度、绑定节点以及在目标Node上启动对应的容器这一完整过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的“部署过程”导致的最终状态。
-
StatefulSet
StatefulSet用于管理有状态应用程序,比如MySQL集群、MongonDB集群、Zookeeper集群等。
StatefulSet的主要特性如下:- StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PersistentVolume来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据安全)。
- 有序收缩、有序删除
- 有序部署、有序扩展,即Pod是有顺序的,在部署或扩展的时候要依据定义的顺序依次进行(从0到N-1,在下一个Pod运行前,所有之前的Pod必须都是Running和Ready状态),基于init containers来实现。
-
后台支撑服务集(DaemonSet)
DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:- 日志收集守护程序,比如 logstash、fluentd等
- 系统监控,比如 Prometheus Node Exporter
- 集群存储后台进程,比如glusterd、ceph等
- 系统程序,比如kube-proxy、kube-dns、glusterd、ceph等
-
一次性任务(Job)
Job负责批量处理短暂的一次性任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
k8s支持以下几种Job:- 非并行任务。
- 具有固定完成计数要求的并行任务。
- 带有工作队列的并行任务。
-
命名空间
命名空间是k8s系统中的另一个重要概念,通过将系统内部的对象分配到不同的命名空间中,形成逻辑上的不同项目、用户组,从而使得在共享使用整个集群的资源的同时还能分别管理它们。
k8s集群在启动后,会创建一个名为default的默认命名空间,如果不特别指明命名空间,那么用户创建的Pod、RC、服务都会被系统创建到默认的命名空间中。默认情况下,相同命名空间中的对象将具有相同的访问控制策略。
yaml文件书写格式
k8s集群中对资源管理和资源对象编排部署都可以通过声明样式(yaml)文件来解决,也就是可以把需要对资源对象操作编辑到yaml格式文件中,我们把文件叫做资源清单文件,通过kubectl命令直接使用资源清单文件就可以实现对大量的资源对象进行编排部署了。
yaml基本语法
- 使用空格作为缩进
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 低版本缩进时不允许使用Tab键,只允许使用空格
- 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
- 使用 —表示新的yaml文件开始
yaml支持的数据结构
- 对象
键值对的集合,又称为映射/哈希/字典
#对象类型:对象的一组键值对,使用冒号结构表示
apiVersion: apps/v1
kind: Deployment
- 数组
一组按次序排列的值,又称为序列/列表
# 数组类型:一组连词线开头的行,构成一个数组
ports:
- protocol: TCP
- 纯量
单个的、最基本的不可再分的值
# 数值直接以字面量的形似表示
number:12.90
# 布尔值用true和false表示
isSet: true
# null用~表示
parent: ~
# 时间采用ISO8601格式
iso8601: 2021-12-12t21:39:43.10-05:00
# 日期采用复合iso8601格式的年、月、日表示
date:1921-09-01
# 字符串默认不使用引号表示
str :这是一个字符串
#如果字符串之中包含空格或特殊字符,需要放在引号之中
str:'内容: 顶顶顶'
# 单引号之中如果还有单引号,必须连续使用两个单引号转义
str:'labor ''s day'
# 单引号和双引号都可以使用,双引号不会对特殊字符转义
s1:'内容\n字符串'
s2:"内容\n字符串"
# 字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格
str: 这是一段
多行
字符串
使用Minikube部署本地k8s集群
在大部分情况下,我们需要在本地玩转k8s,以便于k8s应用程序的开发和调试。搭建完整的k8s集群毕竟太重,使用Minikube则是不二之选。
Minikube是一个轻量级k8s实现,会在本机创建一台虚拟机,并部署一个只包含一个节点的简单集群。Minikube适用于Linux、Mac OS和WIndows系统。Minikube CLI提供了集群的基本引导操作,包括启动、停止】状态和删除。
官网如下:https://minikube.sigs.k8s.io/docs/start/
- 启动Minikube
minikube.exe start --registry-mirror=https://registry.docker-cn.com --vm-driver=“hyperv” --memory=4096 --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers
其中–registry-mirror用于设置镜像服务地址, --image-repository用于设置阿里云镜像,–vm-driver用于设置虚拟机参数,默认是VitrualBox,–memory设置虚拟机内存。
执行上述命令成功之后,我们便可以使用kubectl来操作集群了,例如查看当前所有Pod的状态:kubectl get Pods --all-namespaces
- 打开Minukube可视化面板
minikube dashboard
使用kubectl管理k8s集群
kubectl工具是k8s集群的命令行工具,通过kubectl工具能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。kubectl的配置文件在$HOME/.kube目录。我们可以通过设置KUBECONFIG环境变量或设置命令参数–kubeconfig来指定其他文职的kubeconfig文件。
- kubectl命令的语法
kubectl [command] [TYPE] [NAME] [flags]
-
command:指定要对资源执行的操作,例如create、get、set、delete。
-
type:指定资源类型,资源类型是不区分大小写的,开发者能够以单数、复数和缩略的形式。例如:
kubectl get pods pod1
-
name:指定资源的名称,名称大小写敏感。如果省略名称,则会显示所有资源。例如:
kubectl get pods
-
flags:指定可选的参数。例如,可用-s或-server参数指定k8s api server的地址和端口。
- kubectl子命令使用分类
-
基础命令
-
部署和集群管理命令
-
故障和调试命令
-
其他命令
使用kubeadm创建集群
kubeadm是一个命令行工具,提供“kubeadm init”和“kubeadm join”两个命令来快速创建和初始化k8s集群。
kubeadm通过执行必要的操作来启动和运行一个最小可用的集群。它被故意设计为只关心自动集群,而不是之前的节点准备工作。同样的,诸如安装各种各样的插件,例如k8s Dashboard、监控解决方案以及特定云提供商的插件,这些都不在它的负责范围。
开始部署
首先,我们在腾讯云或阿里云上买台低配的服务器,然后登陆该服务器。
-
主机和IP设置
各节点主机名称和IP设置如下表所示:主机名称 IP k8s-master 172.16.2.201 k8s-node1 172.16.2.202 k8s-node2 172.16.2.203 接下来我们以k8s-master为例进行讲述:
- 设置主机名称以及修改主机记录
# 查看Host名称 hostname # 设置Host名称 hostnamectl set-hostname k8s-master # 修改Host文件,给127.0.0.1添加hostname echo "127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 172.16.2.201 k8s-master 172.16.2.202 k8s-node1 172.16.2.203 k8s-node2" | sudo tee -a /etc/hosts # 查看修改结果 cat /etc/hosts
echo “127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 172.16.2.201 k8s-master 172.16.2.202 k8s-node1 172.16.2.203 k8s-node2” | sudo tee -a /etc/hosts
这段代码是用来修改 Linux 系统中的/etc/hosts
文件,将新的 IP 地址和主机名映射添加到文件末尾。具体来说,这个命令的各部分功能如下:echo
命令:
echo
命令用于生成字符串,然后输出到标准输出(通常是终端)。- 在这个例子中,
echo
输出的是多行文本,包含多个 IP 地址和对应的主机名。
- 管道
|
:
- 管道符号
|
是用来将一个命令的输出传递给另一个命令的输入。在这里,它把echo
命令的输出传递给tee
命令。
sudo
命令:
sudo
命令用于以超级用户(root)权限执行命令,这对于修改系统文件(如/etc/hosts
)是必要的,因为通常只有 root 用户才有权限写入这些文件。
tee
命令:
tee
命令读取标准输入,并将其内容写入到文件和标准输出。这允许你在屏幕上看到正在写入文件的内容。-a
选项告诉tee
命令追加数据到文件末尾,而不是覆盖现有内容。
/etc/hosts
文件:
/etc/hosts
是一个系统文件,用于手动将 IP 地址映射到主机名。这在 DNS 解析不可用时非常有用,也被某些安全和网络配置策略所使用。
解释代码中的具体内容:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
:- 这行指定了
127.0.0.1
(本机地址)对应多个本地的 hostnames。 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
:- 类似地,这行指定了 IPv6 的本机地址
::1
对应的 hostnames。 172.16.2.201 k8s-master
:- 将 IP 地址
172.16.2.201
映射到主机名k8s-master
,这可能是 Kubernetes 集群的主节点。 172.16.2.202 k8s-node1
和172.16.2.203 k8s-node2
:- 这两行将指定的 IP 地址映射到对应的 Kubernetes 集群节点。
- 通过此命令,你可以在不直接编辑
/etc/hosts
文件的情况下,安全地添加新的主机名和 IP 映射。这对于配置网络和服务器,尤其是在设置如 Kubernetes 集群的环境中非常有用。
具体步骤,大家可以参考下面这篇博客:https://blog.youkuaiyun.com/xmcy001122/article/details/127221661
- 设置主机名称以及修改主机记录