得益于 docker 的特性,服务的创建和销毁变得非常快速、简单。Kubernetes 正是以此为基础,实现了集群规模的管理、编排方案,使应用的发布、重启、扩缩容能够自动化。本篇介绍Kubernetes的核心设计。
目录
-
- 1. 编排抽象
-
- Pod对象
- Service对象
- 2. 声明式API
- 3. 开放插件
总结Kubernetes核心设计主要概况为如下三点:
1. 编排抽象
容器平台核心点不在于创建和调度容器,而是在上层架构抽象出各种对象,便于去统一管理。Kubernetes创造性的抽象出了各个编排的关系,例如亲密关系(Pod对象)、访问关系(Service对象)等。
Pod对象
Pod 直译是豆荚,可以把容器想像成豆荚里的豆子,把一个或多个关系紧密的豆子包在一起就是豆荚(一个 Pod)。在 k8s 中我们不会直接操作容器,而是把容器包装成 Pod 再进行管理。
Kubernetes在对象抽象方面,核心创新在于Pod对象的设计。
Pod是 Kubernetes 项目中最小的 API 对象。换句话说Pod是Kubernetes最基本的操作单元,包含一个或多个紧密相关的容器,一个Pod可以被一个容器化的环境看作应用层的“逻辑宿主机”;
一个Pod中的多个容器应用通常是紧密耦合的,Pod在Node上被创建、启动或者销毁;
每个Pod里运行着一个特殊的被称之为Pause
的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此他们之间通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中。同一个Pod里的容器之间仅需通过localhost就能互相通信。
一个Pod中的应用容器共享同一组资源:
- PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID;
- 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围;
- IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信;
- UTS命名空间:Pod中的多个容器共享一个主机名;
- Volumes(共享存储卷):Pod中的各个容器可以访问在Pod级别定义的Volumes;
Pod的生命周期通过Replication Controller
来管理;通过模板进行定义,然后分配到一个Node上运行,在Pod所包含容器运行结束后,Pod结束(其中, pod.status.phase,就是 Pod 的当前状态,它有如下几种可能的情况:Pending
、Running
、Succeeded
、Failed
、Unknown
)。
POD操作示例:
–创建一个nginx pod
kubectl run ng --image=nginx:1.9 --port=80
–状态检查
kubectl get pod name kubectl describe pod name kubectl logs name
–通过yaml创建pod,通过–dry-run来生成一个yaml文件
kubectl run ng --image=nginx:1.9 --port=80 --dry-run=client -o yaml >ng.yaml
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: ng name: ng spec: containers: - image: nginx:1.9 name: ng ports: - containerPort: 80 resources: { } dnsPolicy: ClusterFirst restartPolicy: Always status: { }
–一个pod运行多个容器
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: ng01 name: multi-pod spec: containers: - image: nginx:1.9 name: ng01 ports: - containerPort: 80 resources: { } - image: tomcat:8.0.41-jre8-alpine name: tomcat8-1 ports: - containerPort: 8080 resources: { } dnsPolicy: ClusterFirst restartPolicy: Always status: { }
这个容器运行了两个容器nginx
和tomcat
,执行kubectl apply -f multi.yaml
后,查看pod。
–删除pod
kubectl delete pod ng
Service对象
Kubernetes编排抽象的另一个核心对象是Service对象。
在Kubernetes的世界里,虽然每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失,这就引出一个问题:如果有一组Pod组成一个集群来提供服务,那么如何来访问它呢?
Service!一个Service可以看作一组提供相同服务的Pod的对外访问接口,Service作用于哪些Pod是通过Label Selector来定义的。
下图是kube-proxy通过iptables模式来实现Service的过程,Service对象有一个虚拟clusterIP,集群内请求访问clusterIP时,会由iptables规则负载均衡到后端endpoints。
服务编排通俗地说就是将一个服务在合适的时间放在一个合适的地方,让其按照规划的方式运行。
- 合适的时间:当实际服务状态和预期状态不相符的时候;
- 合适的地方:资源最充足的地方;
- 规划的方式:满足用户的需求;
K8s编排服务工作流程:
- 客户端提交创建请求;
- API Server 筛选合适的节点;
- API Server向指定节点Kubelet下发创建任务;
- Kubelet创建Pod;
- Kubelet上报节点状态。
2. 声明式API
声明式API是整个系统自动化的核心要点,kubernetes提供了以声明式API的方式将抽象对外暴露,同时也方便了用户管理对象。
Declarative
(声明式设计)指的是一种软件设计理念和编程方式,描述了目标状态,由工具自行判断当前状态并执行相关操作至目标状态。声明式强调What,目标是什么。而Imperative(命令式)需要用户描述一系列详细指令来达到期望的目标状态。命令式强调How,具体如何做。
kubernetes的一大核心设计就是采用了声明式API,利用该设计思想有效的实现了系统的自动化运行。Kubernetes声明式API指定了集群期望的运行状态,集群控制器会通过List&Watch机制来获取当前状态,并根据当前状态自动执行相应的操作至目标状态。
Kubernetes中,用户通过提交定义好的API对象来声明期望状态,系统允许有多个API写端,以PATCH方式对API对象进行修改。Kubectl
工具支持三种对象管理方式:命令式命令行、命令式对象配置(yaml)、声明式对象配置(yaml)。举例如下:
- 命令式命令行:
特点:仅需一步就对集群做了修改。示例:创建一个deployment类型的object
kubectl run nginx --image nginx
或
kubectl create deployment nginx --image nginx
- 命令式对象配置:命令式对象配置:
kubectl create –f nginx.yaml kubectl replace –f nginx.yaml
- 声明式对象配置:声明式对象配置:
特点:
1)便捷性:不必添加大量的参数到命令行中执行命令。
2)灵活性:YAML可以创建比命令行更加复杂的结构。
3)可维护性:YAML文件可以通过源头控制,跟踪每次操作;并且对象配置可以存储在源控制系统中(比如Git);对象配置同时也提供了用于创建对象的模板。
kubectl apply –f nginx.yaml
Kubernetes推荐使用:声明式对象配置(YAML)。
3. 开放插件
支持系统资源插件化(比如计算、存储、网络);同时也支持用户自定义CRD和开发Operator。
Kubernetes的设计初衷就是支持可插拔的架构,解决PaaS平台不好用、不能用、需要定制化等问题。为了便于系统的扩展,K8S集成了插件、附加组件、服务和接口来扩展平台的核心功能。附加组件被定义为与环境的其他部分无缝集成的组件,提供类似本机的特性,并扩展集群管理员可用的组件,扩展还可以用于添加自定义软硬件的支持;服务和接口提供了看似繁琐和冗余的设计(比如我们常见的PV、PVC、SC),实际上为开发人员提供了更多的可扩展性。
Kubernetes作为云原生应用的的基础调度平台,相当于云原生的操作系统,为了便于系统的扩展,Kubernetes中开放的以下接口可对系统资源(计算、网络、存储)插件进行扩展,可分别对接不同的后端来实现自己的业务逻辑。
- 网络插件 CNI
CNI(Container Network Interface):容器网络接口,提供网络资源。
跨主机容器间的网络互通已经成为基本要求,K8S网络模型要求所有容器都可以直接使用IP地址与其他容器通信,而无需使用NAT;所有宿主机都可以直接使用IP地址与所有容器通信,而无需使用NAT。反之亦然。容器自己的IP地址,和别人(宿主机或者容器)看到的地址是完全一样的。K8S提供了一个插件规范,称为容器网络接口(CNI),只要满足K8S的基本需求,第三方厂商可以随意使用自己的网络栈,通过使用overlay网络来支持多子网或者一些个性化使用场景,所以出现很多优秀的CNI插件被添加到Kubernetes集群中。 - 容器运行时CRI
CRI(Container Runtime Interface):容器运行时接口,提供计算资源。
CRI接口设计的一个重要原则是只关注接口本身,而不关心具体实现,kubelet就只需要跟这个接口打交道。而作为具体的容器项目,比如Docker、rkt、containerd、kata container它们就只需要自己提供一个该接口的实现,然后对kubelet暴露出gRPC服务即可。简单来说,CRI主要作用就是实现了kubelet和容器运行时之间的解耦。 - 存储接口CSI
CSI(Container Storage Interface):容器存储接口,提供存储资源。
K8S将存储体系抽象出了外部存储组件接口,第三方存储厂商可以发布和部署公开的存储插件,无需接触Kubernetes核心代码,同时为Kubernetes用户提供了更多的存储选项。例如:AWS、NFS、Ceph。
小结:无论多么复杂的应用程序,Kubernetes都可以很好的支持,这使得基于K8S的PaaS平台非常健壮,并且能够更有效地应对现代云计算带来的挑战。
?如果您觉得博主的文章还不错或者有帮助的话,请关注一下博主,如果三连点赞评论收藏就更好啦!谢谢各位大佬给予的支持!