Kubernetes是一个可移植性,可扩展的开源平台,用于管理容器化工作负载和服务,有助于声明性配置和自动化管理。它拥有庞大,快速发展的生态系统。
谷歌在2014年开源了Kubernetes项目。Kubernetes以谷歌在大规模运行生产工作负载方面的15年经验为基础,结合社区的最佳想法和实践。
1.kubernetes是什么意思?
2.我们为什么需要kubernetes以及它可以为我们做些什么?
3.kubernetes是一个怎样的平台?
4.kubernetes不是什么?
5.为什么使用容器?
Kubernetes也称为k8s,kubernetes这个名字来源于希腊语,意为舵手和飞行员,而k8s则是将“ubernete”8个字母替换为“8”而得到的缩写。
kubernetes拥有许多的功能,可以认为它是:
Kubernetes提供了以容器化为中心的管理环境,它代表用户工作负载协调计算,网络和存储基础架构。这提供了平带即服务(PaaS)的简单性,具有基础架构即服务(LaaS)的灵活性,并支持跨基础架构提供商的可移植性。
尽管kubernetes提供了很多的功能,但总会有新的方案从新功能中受益。可以简化特定程序的工作流程,以加快开发人员的速度,最初可接受的特殊编排通常需要大规模的健壮自动化。这就是为什么kubernetes被设计成一个平台,用于构建一个有组件和工具组成的生态系统,使其更容易部署,扩展和管理应用。
此外,kubernetes控制平面基于开发人员和用户可用的相同API构建,用户可以使用自己的API编写控制器,(列如调度程序),这些API可以通过命令行工具进行定位。
这种设计使得许多其他系统能够在Kubernetes上面构建。
Kubernetes不是一个传统的,包罗万象的PaaS(平台即服务),由于Kubernetes在容器级而非硬件级运行,因此它提供了PasS产品常用的一些通用功能,例如:部署,扩展,负载均衡,日志记录和监控。然而,Kubernetes并不是完全统一的,而且这些默认解决方案是可选的和可插入的。Kubernetes为构建开发平台提供了构建快,但在重要的地方保留了用户的选择和灵活性。
Kubernetes:
1:不限制所支持的应用程序类型,Kubernetes的目标是支持多样化的工作负载,有状态和数据处理工作负载,如果有应用程序可以在容器中运行,那么它就可以更好地在Kubernetes上面运行。
2:不部署源代码,也不构建应用程序,持续集成,交付和部署(CI/CD)工作流程由偏好及技术要求决定。
3:不提供应用程序级服务,例如 消息总线 (例如:中间件),数据处理框架,数据库,高速缓存,也不提供集群存储系统(列如:Ceph)。在服务中,这些组件可以在Kubernetes中运行,可以通过便携式机制(列如:Open Service Broker) 在Kubernetes上运行的应用程序访问。
4:不指示记录,监控或警报解决方案。提供了一些集成作为概念证明,以收集和导出标准的机制。
5:不提供或者授权配置语言或者系统(例如:jsonnet)。它提供了一个声明性的API,可以通过任意形式的声明性规范来实现。
6:不提供或采用任何全面的机器配置,维护,管理或者自我修复。
此外,Kubernetes不仅仅是一个编排系统。实际上,它消除了编排的需要。业务流程的技术定义:首先执行A,然后运行B,然后运行C,相反,Kubernetes由一组独立的,可组合的控制流程组成,这些流程将当前状态持续推向所提供的所需状态,从何从A到C无关紧要,也不需要集中控制。这使得系统更易于使用,且功能更加强大,更具有伸缩性和可扩展性。
部署应用程序的旧方法就是使用操作系统软件包管理器在主机上安装应用,这样做的缺点是将应用程序的可执行文件,配置,生命期彼此纠缠在一起,并与主机的操作系统纠缠在一起,可以构建不可变的虚拟机镜像以实现可预测的部署和回滚,但虚拟机是重量级且不可移植的。
而容器则是基于操作系统虚拟化,而不是硬件虚拟化部署的容器,这些容器彼此隔离并与主机隔离,无法看到彼此之间的进程,具有自己的文件系统,并且它们的计算机资源使用受到限制。比虚拟机更容易构建,与底层基础架构和主机文件系统分离,所有它们可以跨云和操作系统进行移植。
由于容器小而快,因此它们每个容器镜像中打包一个应用程序,这种一对一的应用程序到镜像关系解锁了容器的全部优势。使用容器,可以在构建/发布时而不是部署时创建不可变得容器镜像,因为每个应用程序不需要与应用程序的堆栈的其余部署组合。也不需要与生产基础结构环境结合。在构建/发布时容器镜像可以实现从开发到生产环境统一。同样,容器比VM更加透明,有利于监控和管理。容器的流程生命周期由基础架构管理而不是容器内的流程管理。最后,对于每个容器只有一个应用程序,管理容器就相当于管理容器的部署!
kubernetes主要由以下几个组件组成:
详情如下:
kubeadm init --config kubeadm-config.yaml
//或者不指定配置文件
kubeadm init --kubernetes-version=v1.12.0
这两个命令都会执行:
kubeadm reset
kubectl options //查看全局选型
kubectl [command] --help //查看子命令帮助
kubectl explain [RESOURCE] //查看资源的定义
kubectl [command] [PARAMS] -o= //设置输出格式(如 json、yaml、jsonpath 等)
kubectl一些常用命令:
//创建(提供两种方式)
kubectl create -f xxx.yaml
kubectl run xxx --image=xxx
//删除(提供两种方式)
kubectl delete -f xxx.yaml
kubectl delete xxx
//更新(提供两种方式)
kubectl set
kubectl patch
//查询
kubectl get xxx
//容器内执行命令
kubectl exec -it sh
//日志查看
kubectl logs [-f]
REST API
kube-apiserver 支持同时提供 http(6443端口)和 http API(127.0.0.1的8080端口),其中 http API 是非安全的是不建议生产环境使用的.
集群内部与 API Server 的交互
例:与 kube-scheduler,当 scheduler通过 API Server的 Watch接口监听到新建 pod副本的信息后,它就会检索所有符合该 pod要求的 node,开始执行 pod调度逻辑,调度成功之后将 pod绑定到 node上。
与 kubelet进行交互,每个 node上面的 kubelet会每隔一个时间周期,就会调用一次 API Server的 REST接口报告自身状态,API Server则是接收到这些状态,将这些状态保存到 etcd中,此外,kubelet也通过 API Server的 watch接口监听 pod信息,假如监听到新的 pod副本被分配到本节点上,则执行 pod对应的容器创建和启动逻辑,删除以及也是一样。
节点管理主要包括:
pod管理主要包括:
kubelet通过 PodSpec的方式工作,PodSpec是描述一个 Pod的 yaml或者 json对象,kubelet采用一组通过各种机制提供的 PodSpecs(apiserver),并确保这些 PodSpecs描述的 Pod正常运行.
通过 apiserver获取 pod清单并且创建修改 pod过程:
kubelet通过 apiserver client使用 Watch+List 的方式监听 “/registyr/node/$ 当前节点名”和 “/registry/pods”目录是获取的信息获取到同步缓存中,kubelet监听 etcd所有针对 pod的操作都会被 kubelet坚挺到,如果发现有新绑定到本节点的 pod,则按照 pod的清单进行创建.
发现本地的 pod被修改,kubelet会做出更新动作,如:删除 pod中的某个容器,则通过 Docker Client删除该容器,发现删除本节点的 pod,则删除相应的 pod,并且通过 Docker Client删除该 pod中的容器.
这张图出自: https://kubernetes.feisky.xyz/he-xin-yuan-li/index-1/kubelet
Static Pod
所有以非 apiserver方式创建的 pod都叫做 static pod ,kubelet将 static pod的状态汇报给 apiserver,apiserver为该 static pod创建一个 Mirror pod和其相匹配,Mirror pod的状态信息真是反映 static pod的状态,当 static pod被删除时,与之对应的 Mirror Pod也会被删除.
容器运行时
容器运行时(Container Runtime)是 kubernetes最总要的组件之一,真正负责管理镜像和容器的生命周期,kubelet通过 Container Runtime Interface与容器运行时交互,以管理容器和镜像.
Container Runtime Interface它将 kubelet与容器运行时解耦,将原来完全面向 pod级别的内部接口拆分面向 Sandbox和 Container的 gRPC接口,并将镜像管理和容器管理分离到不同的服务.
CRI最早从1.4版本就开始设计讨论和研发,在 v1.5中发布了第一个测试版,在v1.6中已经有了很多外部容器运行时,在 v1.7中又新增了 cri-containerd支持.
kubelet是kubernetes最为核心的部分,这里只写出了一部分,就不一一赘述了,大家可以参考下面网站内容
//https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet
//https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
//https://kubernetes.feisky.xyz/he-xin-yuan-li/index-1/kubelet
这里另外提一个叫做 cloud-controller-manager的控制器,它也是 kube-controller-manager的一部分,稍有不同的是只有用户启动 cloud-Provider的时候才会需要,用来提供云服务供应商的控制,它里面的控制器就比较少了:
高可用:
在启动时设置 --leader-elect=true后,controller manager会使用多节点选主的方式选择主节点,只有主节点才会调用 StartControllers()启动所有控制器,而其他从节点则仅执行选主算法.
多节点选主的实现方法在 leaderelection.go文件它实现了两种资源锁( Endpoint或 ConfigMap,kube-controller-manager和 cloud-controller-manager都使用 Endpoint锁),通过更新资源的 Annotation,来确定主从关系.
高性能:
从 Kubernetes1.7开始,所有需要监控资源变化情况的调用均推荐使
Informer,Informer提供了基于事件通知的只读缓存机制,可以注册资源变化的回调函数,并可以极大减少 API 的调用.
图片出自:https://github.com/cilium/k8s-iptables-diagram
启动 kube-proxy:
kube-proxy --kubeconfig=/var/lib/kubelet/kubeconfig --cluster-cidr=10.240.0.0/12 --feature-gates=ExperimentalCriticalPodAnnotation=true --proxy-mode=iptables
该图出自:https://kubernetes.feisky.xyz/he-xin-yuan-li/index-1/kube-proxy
etcd在这里就没有那么多的事情了,etcd是基于 CoreOS基于 Raft开发的 key-value分布式存储,用于服务发现,共享配置,以及一些分布式锁,选主等.
etcd的主要功能:
Etcd 基于 RAFT 的一致性:
选举方法
初始启动时,节点处于 follower 状态并被设定一个 election timeout,如果在这一时间周期内没有收到来自 leader 的 heartbeat,节点将发起选举:将自己切换为 candidate 之后,向集群中其它 follower 节点发送请求,询问其是否选举自己成为 leader。
当收到来自集群中过半数节点的接受投票后,节点即成为 leader,开始接收保存 client 的数据并向其它的 follower 节点同步日志。如果没有达成一致,则 candidate 随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上 follower 接受的 candidate 将成为 leader
leader 节点依靠定时向 follower 发送 heartbeat 来保持其地位。
任何时候如果其它 follower 在 election timeout 期间都没有收到来自 leader 的 heartbeat,同样会将自己的状态切换为 candidate 并发起选举。每成功选举一次,新 leader 的任期(Term)都会比之前 leader 的任期大 1。
日志复制
当前 Leader 收到客户端的日志(事务请求)后先把该日志追加到本地的 Log 中,然后通过 heartbeat 把该 Entry 同步给其他 Follower,Follower 接收到日志后记录日志然后向 Leader 发送 ACK,当 Leader 收到大多数(n/2+1)Follower 的 ACK 信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个 heartbeat 中 Leader 将通知所有的 Follower 将该日志存储在自己的本地磁盘中。
安全性
安全性是用于保证每个节点都执行相同序列的安全机制,如当某个 Follower 在当前 Leader commit Log 时变得不可用了,稍后可能该 Follower 又会被选举为 Leader,这时新 Leader 可能会用新的 Log 覆盖先前已 committed 的 Log,这就是导致节点执行不同序列;Safety 就是用于保证选举出来的 Leader 一定包含先前 committed Log 的机制;
选举安全性(Election Safety):每个任期(Term)只能选举出一个 Leader
Leader 完整性(Leader Completeness):指 Leader 日志的完整性,当 Log 在任期 Term1 被 Commit 后,那么以后任期 Term2、Term3… 等的 Leader 必须包含该 Log;Raft 在选举阶段就使用 Term 的判断用于保证完整性:当请求投票的该 Candidate 的 Term 较大或 Term 相同 Index 更大则投票,否则拒绝该请求。
失效处理
2)follower 节点不可用:follower 节点不可用的情况相对容易解决。因为集群中的日志内容始终是从 leader 节点同步的,只要这一节点再次加入集群时重新从 leader 节点处复制日志即可。
3)多个 candidate:冲突后 candidate 将随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上 follower 接受的 candidate 将成为 leader
ps:个人认为etcd并不是很难理解,所以没有细写,这里写的etcd出自:https://kubernetes.feisky.xyz/he-xin-yuan-li/index-1/etcd
参考网站:kubernetes.io