一文读懂Kubernetes(K8s)
一、定义
1、k8s是什么
k8s,全称Kubernetes,是一个跨宿主机管理容器的系统(多个小组件组成的软件)
2021百度k8s版本是1.18
2023百度k8s版本升级1.2x
LTS版(长期稳定版)
2、为何要用k8s(云原生)
docker是个啥?
docker是一个容器引擎负责
负责基于容器的三大核心技术(名称空间、cgroup、联合文件系统)来创建容器
但是,创建出容器之后的管理工作,容器引擎做的并不完善
比如:
1、监控容器的存活状态,挂掉了自动重启
2、集群化模式下,把容器调度到最合适的节点上
3、容器的跨宿主机网络通信
- k8s就是为了解决上述的容器管理问题而生的
补充:
云原生:= cloud+Native
cloud:云计算--》资源统一管理形成一个资源池(多个服务器累加的结果)
关键词:资源池、循环利用
各种云平台
提供虚拟机的平台
容器云平台
Native:
应用设计之初就考虑到云环境,或者通过后续的改造去利用云平台的优良特性,来提升软件的质量(比如故障自愈、资源利用)
云原生总结一句话:软件从诞生之初就是专门为了运行在云平台上的
云原生涉及到的技术:
1、微服务
service(负载均衡)
2、Devops
--------定制统一的目标
Dev开发:喜欢更新
Op运维:讨厌更新
3、CICD
CI--代码合并
gitlab代码仓库-----------jenkins平台(流水线)--------》构建得到镜像------》镜像仓库harbor------》目标环境(k8s)
4、容器
3、何时要用k8s
3.1、什么时候使用 Kubernetes
- 你们公司的应用是微服务架构的,或者应用数量较多运维成本大的时候也可以用
- 开发者需要快速部署自己的新功能到测试环境进行验证
- 降低硬件资源成本,提高资源使用率
- 容器自动化管理,故障监控与自愈,自动化部署等
3.2、什么时候不适合使用 Kubernetes
- 应用是轻量级的单体应用,没有高并发的需求
- 团队不适应变革
二、k8s架构、核心概念、组件
1、架构
k8s是一个主从架构
1.1、master节点/主节点
- master节点负责集群的调度、整套k8s集群的维护工作,是k8s集群的总控中心(高可用集群建议部署至少3台Master)
- master节点通过与slave节点不间断通信来维持整个集群的健康状态,若master节点不可用,则我们便无法管理k8s集群中的各种资源
- 集群中各个资源的状态信息存放于etcd分布式数据库中
- Master上部署的组件有apiserver(大脑,唯一能与etcd进行通信)、scheduler(调度)、controller-manager(控制器管理)等管理组件,此外通常还需要部署etcd
1.2、slave节点/从节点/worker节点/node节点
- kubelet会把本节点的资源信息、pod的状态等信息汇报给master的apiserver组件,然后存入etcd中
- kubelet会调用容器引擎来创建容器
- Slave节点上部署有kubelet、kube-proxy、容器引擎等工作组件
2、核心概念与组件
组件:实际存在的软件
资源:组件创建出的逻辑单位,例如namespace、pod、deployment、configmap、 statefulset等
资源:
1、namespace名称空间
名称空间是一门技术,这门技术可以用在不同的地方
容器中用名称空间技术来隔离:pid、ipc、uts、mount、网络、user
k8s中用名称空间技术来把一系列资源隔离到一起(例如pod、deployment、configmap、statefulset)
k8s引入名称空间技术的好处
- 当很多人共用一套k8s集群时,可以用namespace将彼此使用的资源隔离开,互不干扰
- 一组资源被组织到一个namespace中后,更方便k8s进行统一性的管理配置,例如资源配额、访问控制等
Resource Quota限定一个名称空间总共能用多少资源
Limit range现在当前名称空间内,每个pod或者容器的最大资源使用量
2、Pod
2.1、pod是什么?
- pod是一种把相关的容器组织到一起的方式/单位,pod内可以组织一个或多个容器(准确的说一个pod内至少两个容器,一个是pause容器)
- pod是k8s的最小工作/调度单位
2.2、为何要有POD?
为何要引入POD这种概念来组织一下容器,直接管理容器不好吗?
引入POD的好处
1、封装,屏蔽底层容器的差异化(容器引擎的不同)
2、POD内的多个容器共享网络名称空间、共享挂载卷
如果应用由多个容器构成,并且想要实现本地通信,也可能有共享存储的需求
提炼一下pod的两大特性:
1、pod内的多个容器共享网络(网络来自于pause容器)
2、pod内的多个容器共享该pod的存储卷
- 先起一个基于汇编编写的精简的pause容器进行网络设置
- 然后再起相应的业务容器并与pause进行网络共享
- k8s自己对容器进行网络配置,不需要容器来操作
组件:
node节点上:
1、容器引擎:
略
2、kubelet:
1、把本节点的资源信息、pod状态上报给master节点的api server然后存入etcd中
2、接收来自master的创建pod的请求,然后调用容器引擎以及网络插件把pod创建完成
kubelet对接容器引擎
1、在k8s 1.24版之前,可以非常方便的对接docker容器引擎
kubelet –> docker shim (在 kubelet 进程中) –> dockerd –> containerd
2、在k8s 1.24版之后,默认对接的是containerd容器引擎
kubelet –> cri plugin(在 containerd 进程中) –> containerd
对接container的优点:
1、调用路径更短,效率更高
2、k8s的kubelet版本更新迭代更便捷,直接对接cri-containerd即可
3、kubelet的GC机制会负责定期清理工作节点上的镜像以及退出的容器
3、kube-proxy
强调:kube-proxy不负责pod的网络构建,负责的是pod的负载均衡(智能负载均衡、4层),网络是由网络插件实现的
kube-proxy------------------》service资源(智能负载均衡)
负责维护service状态的组件是kube-proxy
service的特点
1、service与pod的动态关联(挂掉pod自动剔除对其的代理,新pod自动添加对其的代理):基于标签来选中
2、service如何实现流量的负载均衡
底层基于ipvs内核转发(与lvs类似)
master节点:
1、etcd分布式数据库:
- 整个k8s的状态都存在etcd中
- etcd是一个分布式key-value存储系统,采用RAFT算法
- 超过半数以上的etcd节点挂掉后,整个etcd集群才不可用
补充:etcd集群的性能决定了集群的规模
2、apiserver:
在k8s中,只有api server可以访问操作etcd,其他组件想操作etcd都必须请求api server,所以apiserver是 整个K8S 集群入口
3、kube-scheduler
创建pod时,scheduler组件会经过两个阶段来完成物理节点的挑选
1、预选(选出符合条件的)
2、优选(选出资源最优的)
4、kube-controller-manager组件
controller控制器--------控制器负责管理维护pod的状态,使其始终处于预期的状态,该过程称之为:调谐(Reconcile)
关系如下:
控制器---------------管理维护-------------pod状态
控制器优多种:
deployment
replicaset
statefulset
cronjob
补充:其实不仅仅是pod资源,几乎每一种k8s的资源都有对应的控制器来负载管理维护
使其始终处于预期状态,完成自动化管理工作
kube-controller-manager组件
内置的控制器都由该组件管理
控制器管理器与控制器的关系如下:
controller-manager---->多种控制器(deployment、statefulset、cronjob等)-----> POD
详解:
controller-manger会通过apiserver访问etcd,来获取每种控制器的状态
一旦控制器的状态不符合预期,就会根据该控制器的特性,来进行调谐的过程
3、List-watch核心机制
List-watch机制:k8s中各组件间协同都采用list-watch机制进行通信
- 客户端首先执行一次list操作来初始化资源状态(一次性操作)
- 然后通过watch操作来持续接收后续的更新
与简单的短轮询相比------->这种机制可以更有效地获取资源状态的更新,并减少了网络流量和APIserver服务器的负载。
创建pod的完整流程
0、controller-manager组件、scheduler组件、kubelet组件都watch监听apiserver、监听自 己关注的资源状态,只要有更新,apiserver就会上报该更新给对应的组件
1、客户端命令kubectl提交创建pod的请求(该pod的控制器采用Replicaset)
2、apiserver收到该请求,会把创建replicaset的请求写入etcd
3、上报事件replicaset created
4、controller-mamanger收到replicaset created事件,进入调谐阶段
controller-mamanger发现当前该pod是0副本,预期要创建1个副本
5、所以controller-mamanger发起要创建一个pod的请求给apiserver
6、apiserver将创建pod的事件存入etcd中
7、apiserver上报Pod created事件
8、scheduler组件收到Pod created事件(因为scheduler一直watch着该资源的变动)
scheduler经过预选与优选来选出一台合适的物理节点来创建新pod
9、scheduler把调度结果(要在某一台物理节点上创建新pod)发送给apiserver
10、将事件存入etcd中
11、上报该事件
12、某一个物理节点上的kubelet会收到该事件,进入pod创建环节
13、kubelet会调用容器引擎以及网络插件创建出pod
(1)kubelet会先调用容器引擎创建出一个pause容器
(2)然后kubelet会调用网络插件来把pause容器的网络打通
(3)kubelet会调用容器引擎来创建出业务容器,并且业务容器采用container网络模式
与pause容器共享网络
补充:关于kubelet如何对接容器引擎的详细如下
如果kubelet对接的docker引擎,对接流程如下
kubelet –> docker shim (在 kubelet 进程中) –> dockerd –> containerd
如果kubelet对接的containerd引擎,对接流程如下
kubelet –> cri plugin(在 containerd 进程中) –> containerd
List-watch的实现
- List:短连接(一次通信完成之后tcp链接就断开,适用于访问频率不高)
- watch:长连接(一次通信完成之后tcp链接依然保留,适用于短时间内频繁访问)
### 组件长时间都处于watch状态,关注实时信息,有可能因为一些网络抖动故障导致watch丢失了某些事件,所以组件会定期发情list操作来获取最新的全量状态,弥补watch的不足
补充:http1.1协议的churnk分片发送(保持长连接)
分块传输编码chunked:
- 不使用分块传输:先告知规定大小,当数据包大小到达指定值后就能知道到这里一个包的内容就结束了
- 使用分块传输:允许服务器在不知道全部响应大小的情况,(比如由数据库动态产生的数据)通过多个小"块"的形式逐步发送HTTP响应给客户端的技术。除非使用了分块编码Transfer-Encoding: chunked,否则响应头首部必须使用Content-Length首部
通过curl模拟watch```bash$ kubectl proxy# 进行listwatch default名称空间下的pods$ curl "127.0.0.1:8001/api/v1/namespaces/default/pods?watch=true"# list出defaullt名称空间下的pods$ curl "127.0.0.1:8001/api/v1/namespaces/default/pods"# 创建pod进行观察$ kubectl run nginx --image=nginx
特性
消息可靠性------list和watch一起保证了消息的可靠性,避免因消息丢失而造成状态不一致场景
消息实时性------每当apiserver的资源产生状态变更事件,都会将事件及时的推送给客户端
消息顺序性------并发的场景下,客户端在短时间内可能会收到同一个资源的多个事件,每 个 资源的事件中都带一个resourceVersion的标签,这个标签是递增的数字
高性能------周期性频繁的轮询大大的增大了开销,增加apiserver的压力;而watch作为异步 消息通知机制,复用一条长链接,保证实时性的同时也保证了性能
三、k8s的部署与应用
2021 百度k8s版本1.18
2023 百度k8s版本1.2x
k8s至今都没有一个长期支持版LTS
k8s有两种安装方式:
1、kubeadm工具
- 容器引擎、kubelet:使用yum安装
- 其他k8s组件:
都被做成了镜像,然后kubeadm会用这些镜像启动相关组件-------》容器
kubeadm会把这些容器做成静态pod(没有控制器管理,挂掉会自动重启)
总结:这些静态pod+容器引擎+kubelet===》构成了k8s环境
所有机器都安装kubectl:只要存在文件,在任意一台机器上都能执行k8s
基于kubeadm安装,master节点也要装kubelet的原因:
1、用于管理master节点上的静态pod的自愈
2、集群规模小的情况下,master节点也会布业务既当master节点又当node节点
2、二进制安装
自己通过yum命令或者源码安装来安装所有组件
部署(略,详见部署文档)