Kubernetes 的高矮胖瘦(介绍)
Kubernetes 是一个 可移植
、可扩展
的开源平台。使用 声明式的配置 依据配置信息自动化执行容器化应用程序的管理。
Traditonal Deployment(传统部署时代):早期,企业直接将应用程序部署在物理机上,由于物理机不能为应用程序定义资源使用边界,很难合理地分配计算资源;
Virtualized Deployment(虚拟化部署时代):用户可以在单台物理机的 CPU 上运行多个虚拟机;
- 虚拟化技术使得应用程序被虚拟机相互分隔开,限制了应用程序之间的非法访问,进而提供了一定程度的安全性;
- 虚拟化技术提高了物理机的资源利用率,可以更容易地安装或更新应用程序,降低了硬件成本,更好地规模化实施;
- 每一个虚拟机都可以被当作虚拟化的物理机上的一台完整机器,上面运行了一台机器的所有组件,包括虚拟机自身的操作系统。
Container Deployment(容器化部署时代):容器与虚拟机类似,但降低了隔离层级,共享了操作系统。因此,容器可以被当作轻量级的
- 与虚拟机类似,每个容器都拥有自己的文件系统、CPU、内存、进程空间等;
- 运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦;
- 容器化应用程序可以跨云服务商、跨 Linux 操作系统发行版进行部署
容器化的优势:
-
敏捷创建和部署应用程序:和创建虚拟机镜像相比,创建容器镜像更容易且快速;
-
持续构建集成:可快速构建容器镜像、部署容器化的应用程序、并轻松无痛回滚应用程序;
-
降低开发和运维的耦合度:开发阶段关注如何构建容器镜像的过程、部署阶段关注如何提供基础设施以及如何使用容器镜像;
-
可监控性:不仅可以查看操作系统级别的资源监控信息,还可以查看应用程序健康状态以及其他信号的监控信息;
-
开发、测试、生产不同阶段的环境一致性;
-
跨云服务商、跨操作系统发行版的可移植性:容器可运行在 Ubuntu、RHEL、CoreOS、CentOS等不同的操作系统发行版上,可以运行在私有化部署、Google Kubernetes Engine、AWS、阿里云等不同的云供应商的环境中;
-
以应用程序为中心的管理:虚拟机时代考虑在虚拟硬件上运行一个操作系统,而容器化时代则是在操作系统的逻辑资源上运行一个应用程序;
-
松耦合、分布式、弹性、无约束的微服务:应用程序被切分成更小的、独立的微服务,并可以动态部署和管理,而不是一个部署在专属机器上的庞大的单片应用程序;
-
资源隔离:确保应用程序性能不受干扰;
-
资源利用:资源高效、高密度利用。
Kubernetes 功能
-
服务发现和负载均衡:Kubernetes 可以通过 DNS 名称或 IP 地址暴露容器的访问方式。并且可以在同组容器内分发负载来实现负载均衡;
- 存储编排:kubernetes 可以自动挂载指定的存储系统
- 自动发布和回滚:可以在 kubernetes 中声明期望应用程序容器达到的状态,kubernetes 将以合适的合适的速率调整容器的实际状态,并逐步达到最终期望的结果
- 自愈:
- 重启已经停机的机器;
- 替换、kill 掉不满足自定义健康检查条件的容器;
- 容器就绪之前,避免调用者发现该容器。
- 密钥及配置管理:
Kubernetes 边界
Kubernetes不是一个传统意义的、保罗万象的 PaaS(Platform as a Service)系统。Kubernetes在容器层面工作,而不是硬件层面,它提供了与 PaaS 平台相似的通用特性,例如:部署、伸缩、负载均衡、日志、监控等。然而,Kubernetes并不是一个单一整体,这些特性都是可选、可插拔的。Kubernetes提供用于搭建开发平台的基础模块,同时为用户提供了不同模块的选择性和多样性。
- 不限制应用程序的类型。Kubernetes的目标是广泛支持不同类型的工作负载,包括:有状态、无状态、数据处理等类型的应用。只要应用可以在容器中运行,就能够非常好地在 Kubernetes 上运行;
- 不部署源码、不编译或构建应用程序。持续集成、分发、部署(CI/CD)的工作流极大程度上取决于组织的文化、偏好以及技术要求。Kubernetes可以作为部署平台参与到 CI/CD 流程,但是不涉及镜像构建和分发的过程;
可选的有 Jenkins / Gitlab Runner / docker registry / harbour 等
- 不提供应用程序级别的服务,包括:中间件(例如,消息总线)、数据处理框架(例如,Spark)、数据库(例如,mysql)、缓存(例如,Redis),或者分布式存储(例如,Ceph)。此类组件可以在 Kubernetes 上运行,或者可以被运行在 Kubernetes 上的应用程序访问;
- 不限定日志、监控、报警的解决方案。Kubernetes 提供一些样例展示如何与日志、监控、报警等组件集成,同时提供收集、导出监控度量(metrics)的一套机制。您可以根据自己的需要选择日志、监控、报警组件;
可选的有 ELK / Prometheus / Graphana / Pinpoint / Skywalking / Metrics Server 等
- 不提供或者限定配置语言(例如,jsonnet)。Kubernetes提供一组声明式的 API,您可以按照自己的方式定义部署信息;
可选的有 helm/kustomize/kubectl/kubernetes dashboard/kuboard/octant/k9s 等
- 不提供或限定任何机器的配置、维护、管理或自愈的系统
可选的组件有 puppet、ansible、open stack 等
Kubernetes不是一个纯粹意义上的容器编排系统。事实上,Kubernetes 消除了容器编排的需求。容器编排的技术定义是预定义流程的执行(先做A、再做B、然后做C)。与此相对应,Kubernetes构建了一系列相互独立、可预排的控制过程,以持续不断地将系统从当前状态调整到声明的目标状态
声明式的配置
声明的方式是相对于非声明方式而言。
以滚动更新为例,假设当下有 3 个容器组,现在需要将它们的容器镜像更新为新的版本
- 非声明方式:
- 使用 kubectl 创建一个新版本镜像的容器组;
- 使用 kubectl 观察新建容器组的状态;
- 新建容器组的状态就绪之后,使用 kubectl 删除一个旧的容器组;
- 重复执行,直到所有容器组都已经替换为新版本镜像的容器组。
- 声明方式:
- 使用 kubectl 更新 Deployment 定义中 spec.template.spec.containers[].image 字段。
以 声明
的方式管理 Pod 和 ReplicaSet,其本质上是将一些特定场景的一系列运维步骤固化下来,以便快速无误的执行。
-
创建 Deployment:创建 Deployment 后,Deployment 控制器将立刻创建一个 ReplicaSet 副本集,并由 ReplicaSet 创建所需要的 Pod;
-
更新 Deployment:更新 Deployment 中 Pod ,此时 Deployment 控制器将为该 Deployment 创建一个新的 ReplicaSet 副本集,并且逐步在新的副本集中创建 Pod,在旧的副本集中删除 Pod,以达到滚动更新的效果;
-
回滚 Deployment:回滚到一个早期 Deployment 版本;
-
伸缩 Deployment:水平扩展 Deployment,来支持更大的负载。或者水平收缩 Deployment,来节省服务器资源;
-
暂停和继续 Deployment:
-
查看 Deployment 状态:
-
清理策略:
-
金丝雀发布:
创建 Deployment
两种创建方式:
- 使用 kubectl 创建 deployment
- 使用 kuboard 创建 deployment
这里我们采用 kubectl
创建方式来完成~
(1)编辑 yaml 文件
## 该 yaml 文件定义了一个 Deployment,该 Deployment 将创建一个有 3 个 nginx Pod 副本的 ReplicaSet(副本集)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment # .metadata.name 字段指定了名称
labels:
app: nginx
spec:
replicas: 3
selector: # .spec.selector 字段指定了 Deployment 如何找到由他管理的 Pod
matchLabels:
app: nginx
template:
# 使用了 Pod template 定义的一个标签(app:nginx),可根据需求添加更复杂的规则
metadata:
labels: # .template.metadata.labels 字段指定了 Pod 的标签
app: nginx
spec:
containers:
- name: nginx # .template.spec.containers[].name 字段表明容器名字为 nginx
image: nginx:1.7.9 # .template.spec.containers[].image 字段表明该 Pod 运行容器 nginx:1.7.9
ports:
- containerPort: 80
(2)执行命令来创建 Deployment
kubectl apply -f nginx-deployment.yaml
## 为该命令增加 --record 选项,kubectl 会将 kubectl apply -f nginx-deployment.yaml --record 写入 Deployment annotation(注解) kubernetes.io/change-cause 中,以便后期回顾某一个 Deployment 版本变化原因
(3)执行 kubectl get deployments
检查 deployment 创建情况,若还在创建过程中,则如下所示:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 0 0 0 1s
字段名称 |
说明 |
NAME |
Deployment name |
DESIRED |
Deployment 期望的 Pod 副本数,即 Deployment 中 .spec.replicas 字段指定的数值,为“期望”值 |
CURRENT |
当前有多少个 Pod 副本数在运行 |
UP-TO-DATE |
Deployment 中,符合当前 Pod Template 定义的 Pod 数量 |
AVAILABLE |
当前对用户可用的 Pod 副本数 |
AGE |
Deployment 部署以来到现在的时长 |
(4)查看 Deployment 的发布状态(rollout status),执行命令 kubectl rollout status deployment.v1.apps/nginx-deployment
(5) 查看 Deployment 创建的 ReplicaSet(rs),执行命令 kubectl get rs
(6) 查看 Pod 的标签,执行命令 kubectl get pods --show-labels
警告:不要修改 Pod-template-hash 标签
更新 Deployment
当且仅当 Deployment 的 Pod template(.spec.template)字段中的内容发生变更时(例如标签、容器的镜像被改变),Deployment 的发布更新(rollout)将被触发。Deployment 中其他字段的变化(例如修改 .spec.replicas 字段)不会触发 Deployment 的发布更新(rollout)
两种途径对 Deployment 执行发布更新(rollout):
- 使用 kubectl 更新 Deployment
- 使用 Kuboard 更新 Deployment
这里我们采用 kubectl
更新方式来完成~
(1)将镜像从 nginx:1.7.9 更新到 nginx:1.9.1
kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
(2)查看发布更新(rollout)的状态
kubectl rollout status deployment.v1.apps/nginx-deployment
查看 更新后 deployment 的情况
(1)更新(rollout)成功后,您可以执行命令 kubectl get deployments
以查看更新结果
(2)执行命令 kubectl get rs Deployment
的更新是通过创建一个新的 3 个副本数的 ReplicaSet 并同时将旧的 Replicaset 的副本数缩容到 0 个副本 来达成的
(3)执行命令 kubectl get pods
,此时将只显示新的 Pod
- 想要修改这些新的 Pod,只需要再次修改 Deployment 的 Pod template
- Deployment 将确保更新过程中,任意时刻只有一定数量的 Pod 被关闭。默认情况下,Deployment 确保至少
.spec.replicas
的 75% 的 Pod 保持可用(25% max unavailable)
- Deployment 将确保更新过程中,任意时刻只有一定数量的 Pod 被创建。默认情况下,Deployment 确保最多
.spec.replicas
的 25% 的 Pod 被创建(25% max surge)
(4)执行命令 kubectl describe deployments 查看 Deployment 详情
创建 Deployment 时,Deployment Controller 创建了一个 ReplicaSet,并直接将其 scale up 到 3 个副本。当更新 Deployment 时,Deployment Controller 先创建一个新的 ReplicaSet 并将其 scale up 到 1 个副本,然后 scale down 旧的 ReplicaSet 到 2。
Deployment Controller 继续 scale up 新的 ReplicaSet 并 scale down 旧的 ReplicaSet,直到最后,新旧两个 ReplicaSet,一个副本数为 3,另一个副本数为 0。
回滚 Deployment
(1)检查 Deployment 更新历史
kubectl rollout history deployment.v1.apps/nginx-deployment
# 检查当前 Deployment 的历史版本
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true
其中,CHANGE-CAUSE 是该 revision(版本)创建时从 Deployment 的 annotation kubernetes.io/change-cause
拷贝来
若需自定义,可通过如下操作完成:
-
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.9.1"
给 Deployment 添加注解
- 执行 kubectl apply 命令,增加
--record
选项
- 手动编辑 Deployment 的
.metadata.annotation
信息
(2)查看 revision(版本)详细信息
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
(3)回滚前一个版本
kubectl rollout undo deployment.v1.apps/nginx-deployment
(4)回滚到前面某一个指定版本
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
## 通过 --to-revision=2 指定版本
(5)检查回滚是否成功
kubectl get deployment nginx-deployment
Kubernetes 大小粗细(组件)
Master 组件
Master 组件是集群的控制平台
- master 组件负责集群中的全局决策(例如,调度);
- master 组件探测并响应集群事件(例如, Deployment 的实际 Pod 副本数未达到
replicas
字段的规定时,启动一个新的 Pod)
kube-apiserver
该组件提供 Kubernetes API。这是Kubernetes控制平台的前端(front-end),可以水平扩展(通过部署更多的实例以达到性能要求)。kubectl / kubernetes dashboard / kuboard 等Kubernetes管理工具就是通过 kubernetes API 实现对 Kubernetes 集群的管理。
etcd
支持一致性和高可用的名值对存储组件,Kubernetes集群的所有配置信息都存储在 etcd 中。
kube-scheduler
master 组件监控所有新创建尚未分配到节点的 Pod,并自动选择为 Pod 选择一个合适的节点去运行。
影响调度的因素有:
- 单个或多个 Pod 的资源需求;
- 硬件、软件、策略的限制;
- 亲和和反亲和(affinity and anti-affinity)的约定;
- 数据本地化要求;
- 工作负载间的相互作用。
kube-controller-manager
此 master 组件运行了所有的控制器
逻辑上说,每一个控制器是一个独立的进程,但为了降低复杂度,可以将这些控制器都合并在一个进程里。
其中包含的控制器有:
- 节点控制器:负责监听节点停机的事件并作出对应响应;
- 副本控制器:负责为集群中的每一个副本控制器对象(Replication Controller Object)维护期望的 Pod 副本数;
- 端点(Endpoints)控制器:负责为端点对象(Endpoint Object,连接 Service 和 Pod)赋值;
- Service Account & Token 控制器:负责为新的名称空间创建 default Service Account 以及 API Access Token;
cloud-controller-manager
cloud-controller-manager 中运行了与具体云基础设施供应商互动的控制器。在 k8s 1.6 版本中引入的特性,它使得云供应商的代码和 Kubernetes 的代码可以各自独立的演化。在后续的版本中,特定于云供应商的代码将有云供应商自行维护,并在运行 kubernetes 时链接到
cloud-controller-manager。
下面这些控制器包含与云供应商相关的依赖:
-
节点控制器:当某一个节点停止响应时,调用云供应商接口,以检查该节点的虚拟机是否已经被云供应商删除
-
路由控制器:在云供应商的基础设施中设定网络路由
-
服务控制器:创建、更新、删除云供应商提供的负载均衡器
-
数据卷控制器:创建、绑定、挂载数据卷,并协调云供应商编排数据卷
Node 组件
Node 组件运行在每一个节点上(包括 master 节点和 worker 节点),负责维护运行中的 Pod 并提供 Kubernetes 运行时环境
kubelet
运行在每一个集群节点上的代理程序。确保 Pod 中的容器处于运行状态,Kubelet 通过多种途径获得 PodSpec 定义,并确保 PodSpec 定义中所描述的容器处于运行和健康的状态。它只管理通过 Kubernetes 创建的容器。
kube-proxy
kube-proxy 是一个网络代理程序,运行在集群中的每一个节点上,是实现 Kubernetes Service 的重要组成部分。
kube-proxy 在节点上维护网络规则。这些网络规则使得可以在集群内、外正确地与 Pod 进行网络通信。如果操作系统中存在
packet filtering layer,kube-proxy 将使用(iptables 代理模式)这一特性,否则的话,kube-proxy 将自行转发网络请求(User space 代理模式)