什么是容器

1
容器的本质是一种特殊的进程。

容器的三要素

1
2
3
4
5
Namespace		#做隔离,让进程只能看到Namespace中的世界;
Cgroups #做限制,让这个“世界”围着一个看不见的墙。
rootfs #做文件系统,rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。

Namespace将集群内部的资源进行隔离划分。在Namespace中,形成逻辑上的不同项目组或用户组。

rootfs

1
2
3
4
5
6
7
8
9
10
11
挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,
叫作:rootfs(根文件系统)。

容器的rootfs由三部分组成,1:只读层、2:可读写层、3:init层
1.只读层:都以增量的方式分别包含了 操作系统的一部分。

2.可读写:就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,
还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,供其他人使用;而与此同时,原先的
只读层里的内容则不会有任何变化。这就是增量 rootfs 的好处。

3.Init 层:是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。

认识kubernetes

1
2
3
4
5
6
7
8
9
Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,方便进行声明式配置和自动化。可以自动部署
(automating deployments),伸缩(scaling)和运维容器化应用(operations of application containers)的开源平台。以下
简称k8s

k8s参考网站
`k8s官方`: https://kubernetes.io/zh-cn/docs/home/
`阿里云k8s-ACK`:https://www.aliyun.com/product/kubernetes
`亚马逊k8s-EKS`:https://aws.amazon.com/cn/eks/?nc2=h_ql_prod_ct_eks
`使用ansible一键部署k8s`:https://github.com/easzlab/kubeasz

k8s组件

components-of-kubernetes

核心组件

1
2
1.控制平面组件(Control Plane Components)  master节点
2.控制容器运行时(docker)启动指定的容器 node节点

k8s各个组件功能说明

(1)UI,CLI

1
2
3
4
5
6
统称API用于发送请求给Kubernetes(K8S)集群。

## K8S三大接口API二次开发,调用接口
CRI:runtime,容器操作接口
CNI:network,网络操作接口
CSI:storage,存储操作接口

(2)Kubernetes Master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
用于处理客户端的发来的请求,根据需求调度后端节点运行任务,就是'老板'存在。其内部核心组件分为:
1.`API Server`(K8S内置组件) '秘书'
提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;
提供API服务的组件,是一个独立的守护进程,是Kubernetes集群的唯一入口(无论是客户端还是内部组件都必须通过它来访
问);它提供基于https(RESTful风格)和rpc协议(grpc是据说是将来要取代Https的RESTful风格)来提供服务的。它用来处理
客户端传来的JSON格式的请求数据而非HTML格式哟。它也是K8S集群唯一能操作etcd的组件

2.`Scheduler`(K8S内置组件) '人事'
负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;
比如客户端通过API Server提交了一个新增容器的请求,该请求保存在etcd中,etcd通过API Server通知Scheduler,
Scheduler接收到通知后会在管理的资源中选择一个最佳运行的节点去创建容器;该指令依旧存放在etcd中(Scheduler不能直
接访问etcd,而是通过API Server间接访问etcd)。

3.`Controller manager`(K8S内置组件)
负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
该组件会watch Api Server组件用于管理K8S集群的组件,确保我们所创建的容器能够按照期望的状态运行的核心组件
(比如:监控集群的所有容器运行,当某个容器挂掉后它可以迅速在另一个节点启动),我们甚至可以说
Controller manager是K8s的大脑。

4.`etcd`(并不是K8S内置组件,由CoreOS研发,被RedHat收购,最终又被IBM公司收购)
etcd只能被API Server直接访问。是整个集群的核心,负责存储K8S请求数据所有的数据。保存了整个集群的状态;
etcd基于raft协议使用Golang语言开发的分布式强一致的键值对(key/value)数据库存储系统。存储方式和redis很像,
但是功能却比redis要强大,因为它支持数据的强一致性,也支持leader选举等各种分布式协同功能。
1
2
3
4
5
6
kube-apiserver(apiserver):#所有Master上的组件工作都要经过apiserver
etcd: #存储所有命令、资源清单、webUI操作及其他组件数据
kube-scheduler(scheduler):#资源计算、资源调度
kube-controller-manager(controller):#维护集群状态

`当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态`

(3)Kubernetes Node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
功能上有点类似于Hadoop中的DataNode节点,被Kubernetes调度的,即负责真正干活的节点(运行容器)。其内部核心组件分为:
1.`kubelet`
负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理;
该组件也会watch Api Server组件,即实时查看关于当前节点的任务,从而去执行创建或删除容器的任务
(以Docker为例,创建容器时就会调用docker的API去Image Registry去下载相应的容器并启动)。
2.`Container runtime `
负责镜像管理以及Pod和容器的真正运行(CRI);
3.`kube-proxy` '监工'
负责为Service提供cluster内部的服务发现和负载均衡;
kube-proxy说白了也是API Server的客户端,它实时监视(watch)着API Server上的资源变动(尤其是service资源变动),
它会把每个service资源变动在相应节点上定义为对外暴露相关规则(iptable或者ipvs),比如对外暴露外网映射之类的。

4.Pod 'Pod是K8S的最小单位'
虽然我们说Kubernetes是容器编排系统,但是不得不说在K8S之上并不会直接运行容器,每个容器在K8S中都被重新封装成pod,说
白了pod就是容器的外壳,但需要注意的是一个pod是可以存在多个容器的。每个pod被K8S当作一个原子单元进行管理;一个pod中
有多个容器,这个pod里面的所有容器只能被调度到一台节点去执行,不能将同一个pod里面的多个容器拆分到不同的Node运行;

1、Pod是K8S的最小单位
2、Pod的IP地址是随机的,删除Pod会改变IP
3、Pod都有一个根容器(一个pod至少有一个根容器)
4、一个Pod内可以由一个容器或多个容器组成
5、一个Pod内的容器共享根容器的网络、名称空间、和文件系统卷
6、一个Pod内的网络地址由根容器提供

5.`Fluentd`
如Fluentd-elasticsearch提供集群日志采集、存储与查询

6.`Image Registry`
存放镜像文件的仓库,并不直接被Kubernetes集群管理,即并不算k8s原生组成部分,通常我们会自建私有的镜像仓库,
比如使用Harbor部署https高可用的镜像仓库
1
2
3
4
5
6
7
kubelet:控制容器运行时(docker)启动指定的容器
容器运行时(Container runtime):docker
- containerd
- CRI-O
- Docker Engine
- Mirantis Container Runtime
kube-proxy:POD端口映射,网络相关

POD运行状态

状态 描述
Pending(等待) Pod已经被K8S系统接受,但是有一个或多个容器,尚未创建,亦未运行。此阶段包括等待Pod被调度的时间和通过网络下载镜像的时间
Running(运行) Pod已经绑定到某个节点(node),Pod中所有容器都已被创建,至少有一个容器仍在运行,或者处于启动或重启状态
Succeeded(成功) Pod中所有容器都已成功终止,并且不会再重启
Failed(失败) Pod中所有容器都已成功终止,并且有一个容器是因为失败而终止
Unknown(未知) 因为某些原因无法获取Pod状态,这种情况,通常是因为与Pod所在主机通信失败

k8s网络

Service也是K8S核心资源之一,Service定义了服务的入口地址,用来将后端的Pod服务暴露给外部的用户 访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubernetes的网络大致分为以下三类:
1.节点网络:
主要是指`Master`和各个`Node`之间进行通信的网络地址段。
 2.pod网络:
    因为每个pod的'动态IP地址',所以每个pod并不知道想要访问的目的pod的IP地址,它们如果想要访问目的pod需要经过一
    个'service'层。这个service有对每个pod的打了'标签',当任意一个节点的pod想要访问另外一个pod必须得过
    'service网络',service网络保存着'标签选择器',可以迅速匹配到pod想要范围另一个pod的真实IP地址,当pod拿到
    IP地址后就可以自行进行通信请求了。
3.service网络:
   主要是为pod提供一个'标签选择器'的功能,比如帮助一个pod去查询访问另外一个pod的label对应的真实IP地址。而
   sevice网络在kubernetes1.11.x版本之前默认使用iptable实现的,在kubernetes 1.11.x版本之后引入了ipvs实现。

'各个pod之间的通信过程概要':
每个pod都有被动态分配的IP地址,如果想要和另外一个pod进行通信,各个pod需要先和service网络进行通信,最终拿到
另一个想要访问pod的动态IP地址进行通信。

Service提供了两种网络资源

image-20240916151114679

1
2
3
4
5
6
7
8
9
10
11
12
NodePort:宿主机端口映射ClusterIP端口对外提供服务

ClusterIP:POD的负载均衡
问题:POD的IP是随机的,如果一个POD宕机了,K8S会自动拉起一个新的POD,IP变化了如何加入到
ClusterIP这个负载均衡集群中?
解决方案:使用DNS解析POD的IP到一个"字符串上"(标签)


DNS:
- coreDNS
- bind9
- dnsmsq

Label标签

1
2
`Label标签`是K8S中非常重要的一个属性,Label标签就像身份证一样,可以用来识别K8S的对象。
传统架构中,不同的服务应用之间通讯,都是通过IP和端口,但是在K8S中很多匹配关系都是通过标签来找。

Controller资源(控制器资源)

1
2
3
4
5
6
7
# Controller用来管理Pod。
## Pod控制器的种类有很多:
- RC Replication Controller 控制Pod有多个副本
- RS ReplicaSet RC控制器的升级版,可以自动拉起宕机的POD
- Deployment 推荐使用,功能强大,包含了RS控制器,对镜像做版本管理
- DaemonSet 保证所有的Node节点上,有且只有一个Pod运行
- StatefulSet 有状态的应用,为Pod提供唯一标识,它可以保证部署和scale的顺序

创建一个pod流程

create-pod

1
2
3
4
5
6
7
8
9
`第一步:`
用户通过kubectl等接口提交创建Pod的yaml文件,向Kubernetes系统发起资源请求
`第二步:`
Api-server接收到用户请求之后,会做出相应的认证,然后检查信息并且将元数据信息存储到etcd中,创建Pod资源初始化,
这是第一次写etcd动作
`第三步:`
Scheduler通过list-watch的监听机制,查看要创建Pod资源,APIServer会立即把创建Pod的消息通知Scheduler,
Scheduler发现Pod的属性中Dest Node为空时(Dest Node=””),便会立即触发调度流程进行调度,而调度流程分为
以下几个步骤,如下图

kube-controller-manager‌:虽然不直接参与Pod的创建,但其内部的控制器(如ReplicaSet Controller)负责确保Pod的数量与预期一致,维护集群状态

scheduler

​ 首先是kube-scheduler调度器用一组规则过滤掉不满足条件的主机,这个过程称为predicate,比如明确指定所需要的资源类型,这样就可以过滤掉不满足条件的主机

​ 其次,对第一步筛选出的符合要求的主机进行打分,这个过程称为 priority,在此阶段,如果在 predicate过程中没有合适的节点,Pod 会一直处于pending状态,不断重试调度,直到有节点满足条件。

选择优先级最高的节点:选择得分最高的主机,进行binding操作,结果存储到Etcd中

1
2
3
4
5
6
7
8
第四步:
kubelet根据调度结果执行Pod创建操作,绑定成功后,会启动容器运行时,container, docker run, scheduler会调用API
Server的API在etcd中创建一个bound Pod对象,它描述在一个工作节点上绑定运行的所有pod信息;
运行在每个工作节点上的kubelet也会定期与api-server同步bound Pod的信息,一旦发现在该工作节点上运行的bound Pod对
象没有更新,则调用Docker API创建并启动pod内的容器.

第五步:
kube-proxy为新创建的pod注册动态DNS到CoreOS,然后给pod的service添加对应的iptables规则,用于服务发现和负载均衡。