本文所涉及的脚本均来自仓库 k-kubernetes-public
闻名不如见面 -- HPA
Horizontal Pod Autoscaling,水平部署自动化弹性伸缩,即 K8s 支持根据 CPU/内存 利用率自动伸缩 Pod 数量,从而动态调整负载。
# 无状态服务部署 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hpa
spec:
replicas: 1
selector:
matchLabels:
app: nginx-hpa
template:
metadata:
name: nginx-hpa
labels: # 必须指定标签
app: nginx-hpa
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
# hpa 生效必须的资源请求配置
resources:
requests:
memory: 50Mi
cpu: 10m # 设置小些,便于增加负载测试
# 暴露 nginx ,便于测试
---
apiVersion: v1
kind: Service
metadata:
name: nodeport-svc
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30001 # 主机 Port
selector: # 必须指定目标标签的pod
app: nginx-hpa
可以用多个 Shell 执行,以提高负载压力,观察 Pod 伸缩动态
echo '----- 部署 Pod ------'
kubectl apply· -f nginx-hpa.yaml
echo '----- 创建 HPA 对象 ...'
kubectl autoscale deployment nginx-hpa --cpu-percent=10 --min=1 --max=10
echo
echo '----- 增加负载 ...'
curTime=`date '+%s'`
while true; do
wget -q -O- http://localhost:30001;
done
- cpu-percent cpu利用率
- min/max Pod数量限制
Docker 所不能
这是原生Docker无法实现的,虽然通过脚本或扩展API等方式可以间接实现,但每家公司、每个团队类似的操作、不同的实现,不仅冗余、而且水平参差不齐,并不具备大规模生产推广的能力。
走进 Kubernates - 架构
- 架构:控制面 + 数据面
Kubernates 采用经典的分布式任务系统HA架构,将整个系统鲜明的划分为负责集群管理/调度的逻辑控制面(Control Pane)和执行实际指令/工作的数据面(Data Pane),且每个层面均采用稳定性更高的多进程(相比于多线程)设计,每个功能一个独立的进程,单个进程的崩溃并不影响的系统的其他进程正常工作。且为保证功能的高可用性。且每个功能均采用 HA 方案,如 Etcd HA集群,单个或少数进程的崩溃并不会影响该功能的整体工作。
控制面 Control Pane
承载整个系统资源和状态管理、调度逻辑的多个功能组件(进程)的集合,相当于集群的大脑🧠(控制中枢),其部署和运行并不和受管理的集群Node耦合,也不要求每个Node上部署。
通常包含以下内置组件和扩展组件:
API Server (管理)接口服务器
外界(客户端)和K8s集群交互的唯一入口,负责接收客户端的请求(如创建部署 Pod),根据调度策略(如标签选择)进行部署和调度容器(Scheduler),将集群的状态向目标状态进行迁移(Etcd)。
如通过命令行客户端查看pod(本质是向Api Server 发送 Rest 请求)
kubectl get pods -n kube-system
API Server 客户端/UI
外部用户通过各类客户端或Dashboard 与 APiServer 交互以实现对集群的管理,如创建账户、部署服务等,亦可算作广义的控制面范畴,其本质均是调用 ApiServer 的资源 Rest Api 来实现特定资源的CRUD操作。
- 客户端 kubectl - 新手推荐
基于 ApiServer Rest Api 封装的命令行客户端,可以通过脚本实现对特定资源的 CRUD 操作,适合扩展,如编写批量关联的脚本。新手推荐,以更好的理解 Kubenates 集群舵手的实质。fast-kubectl
- Kubernates Dashboard - 官方、轻简
Kubernates 官方提供的轻量级Dashboard,可满足小规模集群的常用管理操作。一键安装
- Rancher UI - 商业、强大
Rancher是一款强大的容器编排和调度系统,2.x 版本底层基于k8s调度引擎,通过Rancher的封装,屏蔽底层K8s复杂的概念和架构,即便是不懂K8s复杂概念的用户也可以轻松的通过Rancher来部署容器到k8s集群当中。
相比于Kubernates Dashboard ,Rancher 处理可以编排集群上的容器外,更支持多k8s集群的部署和管理,从而将多集群的管理和使用整合在统一的Rancher平台中。同时 Rancher 支持丰富的扩展插件,以动态插拔各种高阶功能。一键安装
Etcd 分布式键值数据库
API Server 中所需要的这些元信息都被放置在 etcd 中,如各类Secret 密文配置 、Config 明文配置、Service服务等均以 Key-Value 的形式保存在 Etcd 集群中,即便 Api Server 崩溃也不影响集群数据本身的安全性。
Etcd 作为独立的存储,也可以直接通过其客户端Api查看集群中保存的各类信息,因此例如 Secret 等敏感信息,最好采用额外的加密方案进行保存,否则一旦泄漏,则危及整个 Kubenates 集群以及上层业务应用的安全。
查看 kube-system 命名空间下注册的组件
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 get /registry/serviceaccounts/kube-system --prefix --keys-only
Scheduler 资源调度器
Kubenates 集群本质是所有节点、CPU、内存、存储等各类资源的集合,Scheduler 的核心目标即根据各种资源分配和优化策略,选择最佳的节点Node部署目标Pod,从而既满足 Pod 本身的部署要求,也合理安排整个集群的各类资源和负载,类似于 Hadoop 体系中的 Yarn。
为了保证资源调度的合理性和扩展性,Scheduler 设计了一套由 Predicate(过滤器)、Priority(优先级排名)自由组合的调度算法。同时针对 Pod 和 Node 的动态绑定,设计了基于标签选择器的 亲和-污点-容忍 机制,避免直接绑定的强耦合机制。
apiVersion: apps/v1
kind: Deployment
metadata:
name: direct-selector-deploy
spec:
replicas: 1
selector:
matchLabels:
app: direct-selector-pod
template:
metadata:
name: direct-selector
labels:
app: direct-selector-pod
spec:
# 直接指定 标签选择器,限制指定cpu架构的主机才能部署
nodeSelector:
# kubernetes.io/arch: x86 # ❌ mac amd64 上无法安装
kubernetes.io/arch: amd64 # ✅ mac amd64 上可以安装
containers:
- name: direct-selector
image: busybox
command: [ "sleep", "10000" ]
Controller Manager (资源)控制器 - 管理器
管理集群中的各种资源控制器,这些资源制器负责维护和管理集群上部署的各种资源及其状态迁移和控制,比如副本期望数量、故障检测、自动扩展、滚动更新等。
资源控制器工作原理是通过 API Server + Etcd 监视集群中特定资源的状态,如Pod新建、修改,并尝试修改系统当前状态转为期望状态(如部部署新的Pod以达到新的目标数量)。
资源控制器遵循单一职责设计原则,每个资源控制器只针对特定资源如Deployment或ServiceAccount进行状态追踪和管理,因此从逻辑上讲,每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行,即 Controller Manager 中统一运行所有的控制器。
-
内置控制器
针对Kubernates自带的系统级资源,如 ServiceAccount 服务账务、Pod 部署包等,均内置了特定的控制器,已达到控制和响应资源状态的目的。
- 服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌
- 节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
- 部署类资源控制器: 针对不同的部署场景和应用形态,Kubernates 提供 Pod、Deployment 等多种部署资源及其对应的内置控制器,如 Deployment Controller。 实战源码
- 任务控制器(Job controller): 监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
- 端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)
- ...
-
自定义控制器
Kubernates 提供自定义资源CRD(Custom Definition Resource)机制,并可以针对其扩展相应的管理控制器,最经典的当属 L7层负载均衡资源 - Ingress 的控制器 - Nginx Ingress Controller 。
数据面/工作面 Data Pane
和控制面不同的是,控制面的组件通常部署在每个受控的 Node 上,作为 agent 接收来自控制面组件的指令、执行特定的本地化工作,如 ApiServer(控制面)创建 Pod,最终由特定节点上的 kubelet 代理本地部署工作。
- Container Runtime 容器运行环境(基础) 是负责运行容器的软件,k8s通过CRI(容器运行环境接口)机制支持多个容器运行环境,Docker、RKT
-
kubelet(最核心) 本地化部署 agent,负责维护本节点上容器的生命周期,并上报 pod 运行状态,同时也负责 Volume 和网络(如调用 CNI插件组件为Pod分配IP)的管理。
-
kube-proxy(服务发现与LB) 真正完成 service 组网,利用了 iptable/ipvs 的能力来进行组建 Kubernetes 的 Network,并实现 负载均衡LB、内网通信等高阶网络功能。
- ...
一切皆资源 - Resource
分布式运维集群的本质是各类软(如运维账户、配置)、硬件(如CPU、内存)资源的集合以及针对这些资源的CRUD操作,因此 Kubernates 中 Resource 是一等对象,所有受控制面(ApiServer)关联的对象均是可操作的Resource对象,如 Pod、Service 等,而 Kubernates 系统组件和架构的设计也是以面向资源的CRUD为核心的,即 高动态集群运维模型
内置资源
Kubernates 内置各种常见的运维资源对象,大致可分为:
- 集群级别的资源: Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
-
工作负载类型资源(workload)
- Pod: Kubernetes中最小的负载单元
- ReplicaSet:简称RC,管理Pod的创建,通过标签控制副本数,在v1.11之后被废弃,新版使用 ReplicaController
- Deployment:无状态部署,通过控制ReplicaController去创建Pod,用于无状态的服务
- StatefulSet:有状态部署,主要用于有状态服务
- DaemonSet:在每个节点都运行一个Pod组件
- Job、CronJob:为了(批)处理
-
服务发现及负载均衡资源(Service Discovery And LoadBalance)
- Service:
- Ingress...
-
配置与存储类型
- Volume(存储卷)
- CSI(容器存储接口,可以扩展各种各样的第三方存储卷,现在市面上的大多数存储都是支持CSI。)
- 特殊类型的存储卷
- ConfigMap(当成配置中心来使用的资源类型
- Secret(保存敏感数据)
- DownwardAPI(把外部环境中的信息输出给环境,比如把运行Pod的所在Node的NodeIp传进Pod)
-
元数据(metadata):HPA、PodTemplate、LimitRange(资源限制)
4大基本资源
虽然上述大大小小数十内置和扩展的资源对象,但一个 k8s 分布式运维集群本质上是由 Namespace、Volume、Pod、Service 4大基本资源对象组成的,其他资源对象不过是这些基本对象的逻辑组合。
Pod 负载部署资源
k8s 对部署在集群Node中、需要占用一定的集群资源(cpu、内存),提供某种计算负载能力、并受 k8s 管理的进程的抽象。
Pod 是Kubernates 上容器化服务的最小部署单位,k8s 利用pod屏蔽底层不同容器技术的差异,同时代理k8s对服务资源占用和调度的逻辑。
Volume 存储资源
Volume 是 Kubernetes 对存储资源的抽象,代表可以被K8s管理、Pod使用的存储空间。K8s不仅仅可以利用本地存储,更支持插件机制集成各种主流的云存储,如阿里云上的云盘、AWS 上的云盘、Google 上的云盘,扩展无限空间。
Service (网络)服务资源
k8s 中对标 微服务Service 的概念,本质是为一组动态的对等或相关(多进程服务) Pod集合提供对外一致的服务标记(服务名),从而在集群内天然实现服务发现(微服务的核心)的能力。可以说,k8s 是天然为 微服务架构而生的,也很适合无状态的微服务架构的分布式HA部署。
Namespace 命名空间/子集群
Volume-Pod-Service 构成了K8s是一个完整服务的三元组,但一个k8s集群上总是部署数十、数百不同的服务,如何隔离这些服务及其资源,以保证安全、稳定的运行环境呢? K8s的解决方案 -- Namespace 命名空间/子集群,即将一个物理 Cluster 逻辑上划分成多个逻辑的、隔离的子 Cluster,每个子 Cluster 就是一个 Namespace。不同 Namespace 里的资源是完全隔离的,从而保证各应用可以在相对稳定的子集群中健康、稳定、持续运行,不用担心其他应用的资源抢占和污染。
每个应用的多个进程通常被部署在一个相对独立的命名空间中,如 Kubernates 系统组件通常部署在内置命名空间 kube-system 中
- 内置/默认
- kube-system K8S 系统组件和三方管理组件均部署在此命名空间,如 Kubernates Dashboard
- kube-node-lease 供监视 K8S 状态第三方插件使用
- kube-public 供 公共资源 使用
- default 新创建资源默认属于此命名空间
高扩展 REST API
Kubernates 采用 REST API 规范,对集群上部署的各类资源进行CRUD操作(Verbs),简洁易用,易于扩展。
Verbs 资源动作
即该来资源支持的crud操作,如 Pod 资源的 create、delete、list 等操作,这些动作本身是细粒度的权限单位,在RBAC鉴权机制下用于为指定的角色绑定特定资源的权限。
# 创建集群私密功能的集群角色:秘钥只读
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# 集群级别 无需 namespace
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
API Group API组
在 k8s 中为了提高 API 的可扩展性,采用了 API Groups 进行标识资源对应api所在的分组 -- 即增加了一层逻辑扩展点。 当前 k8s 支持两类 API Groups:
- Core Groups(核心组)
也称为 Legacy Groups,作为 k8s 最核心的 API ,其特点是没有组(无组也是组)。Kubernates 内置核心资源的API通常在此分组,如 Pod、Service。
- 其他分组
以/apis/$GROUP_NAME/$VERSION
路径标记,携带分组、版本标志的API,这些分组常用于特定目的的资源API,如服务部署相关的apps分组、批处理任务相关的batch分组等。
VERSION 版本标记,用于标记一个资源及其API的成长计划,一个新的资源总遵循设计 -> 引入 -> 测试 -> 成熟/废弃
的成长路线,因此 Kubernates 以此标记,即一个资源及其API在不同版本的K8s中并非总是一个固定的版本,因此要针对k8s版本调整对应资源的版本。
- Alpha 非安全版本,开发者应该谨慎使用该资源,并承担相应的风险
- Beta 测试版,已经过
Alpha
的测试,相对稳定,但仍需广泛的生产实践 - vN 稳定版,N=1,2...以经过大规模生产验证的版本,开发者可以放心使用该资源及其API
常见的API分组如
-
rbac.authorization.k8s.io/v1 RBAC 基于角色的权限管理类资源的分组
- Role、ClusterRole
- RoleBinding、ClusterRoleBinding
-
apps/v1 用于部署相关的资源API
- DaemonSet
- Deployment
- StatefulSet
- ReplicaSet
-
batch/v1 批处理任务相关资源的API
- Job
-
batch/v1beta 批处理任务相关,但仍处于测试期的资源API
- CronJob
总结
通过上述可以看出,K8s是一个优秀的、面向资源的分布式集群 - 自助化运维舵手,其高可用的架构和高扩展的REST API,奠定了其广泛流行的技术基础,并逐渐从同类框架中脱颖而出、成为容器编排的企业级方案的事实标准。