本文大部分是原理,后期打算开个专栏,咱也玩玩知识付费~
在云计算领域有几个很常见的词汇:IaaS、PaaS、SaaS。IaaS就是基础平台即服务,国内有阿里云等;PaaS是平台即服务,在早些时候新浪云SAE较为有名;SaaS就是软件即服务,最大的Office厂商MS的Office365就是一个很好的代表。在最开始的时候PaaS基本就是人肉运维,慢慢的又出现了一系列的自动化工具,再后来专门做PaaS的一家公司创造了Docker。Docker变成了PaaS的一个标准,但是随着容器化的发展也出现了一系列的问题。容器化后容器的映射关系变得异常艰难,而且这仅仅是容器化发展的一个小小的问题。那么随着容器化的步伐,衍生出了一些列的资源管理器,最开始是Apache Mesos,Mesos由加州的伯克利大学研发出来,随后被推特选中,大规模的在推特盛行。在2019年5月,特推在旧金山开展了技术发布会,在该会上产品负责人宣布推特以后全部使用Kubernetes。第二款资源管理软件是Docker自家推出的Docker Swarm平台。Docker Swarm是一个非常轻量的资源管理平台。但是Swarm功能较为简单,而且国内云厂商阿里云在2019年7月宣布在选择资源管理框架的时候不支持Swarm,默认Kubernetes。Google其实在Kubernetes诞生10年前就使用了容器化基础架构Borg。Google为了在资源管理器上占有优势,就使用Golang开发了Kubernetes。
类似于Borg系统,Kubernetes的架构如下:
Pod分为自主式Pod和控制器管理的Pod,自主式Pod一旦死亡就会无法拉起。在Pod中,有一个容器叫做pause,只有存在Pod,该容器就会启动。在该Pod中的其他容器公用pause的网络栈和存储卷,因此在同一个Pod里容器的端口不能冲突。
Replication Controller用来确保容器应用的副本数量始终保持在用户定义的副本数量上,如果容器异常退出,那么将会创建新的Pod来替代,如果创建过多,过多的Pod将会被回收。在新版本的Kubernetes中,建议使用ReplicaSet取代Replication Controller,原因是RS支持标签操作。RS支持集合式的Selector。
虽然ReplicaSet可以独立使用,但是还是建议使用Deployment来自动管理RS,这样无需担心跟其他机制的不兼容问题。
Deployment继承了上面描述的Replication Controller全部功能。还支持事件和状态查看,回滚,版本记录,暂停和启动。
HPA(Horizontal Pod Autoscaling)仅适用于Deployment和ReplicaSet,在v1版本中仅支持根据Pod的CPU利用率扩容。
HPA(Horizontal Pod Autoscaler)是kubernetes(以下简称k8s)的一种资源对象,能够根据某些指标对在statefulSet、replicaController、replicaSet等集合中的pod数量进行动态伸缩,使运行在上面的服务对指标的变化有一定的自适应能力。
HPA目前支持四种类型的指标,分别是Resource、Object、External、Pods。其中在稳定版本autoscaling/v1中只支持对CPU指标的动态伸缩,在测试版本autoscaling/v2beta2中支持memory和自定义指标的动态伸缩,并以annotation的方式工作在autoscaling/v1版本中。
HPA在k8s中的结构:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
# HPA的伸缩对象描述,HPA会动态修改该对象的pod数量
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
# HPA的最小pod数量和最大pod数量
minReplicas: 1
maxReplicas: 10
# 监控的指标数组,支持多种类型的指标共存
metrics:
# Object类型的指标
- type: Object
object:
metric:
# 指标名称
name: requests-per-second
# 监控指标的对象描述,指标数据来源于该对象
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
# Value类型的目标值,Object类型的指标只支持Value和AverageValue类型的目标值
target:
type: Value
value: 10k
# Resource类型的指标
- type: Resource
resource:
name: cpu
# Utilization类型的目标值,Resource类型的指标只支持Utilization和AverageValue类型的目标值
target:
type: Utilization
averageUtilization: 50
# Pods类型的指标
- type: Pods
pods:
metric:
name: packets-per-second
# AverageValue类型的目标值,Pods指标类型下只支持AverageValue类型的目标值
target:
type: AverageValue
averageValue: 1k
# External类型的指标
- type: External
external:
metric:
name: queue_messages_ready
# 该字段与第三方的指标标签相关联,(此处官方文档有问题,正确的写法如下)
selector:
matchLabels:
env: "stage"
app: "myapp"
# External指标类型下只支持Value和AverageValue类型的目标值
target:
type: AverageValue
averageValue: 30
HPA的特性结合第三方的监控应用,使得部署在HPA伸缩对象(statefulSet、replicaController、replicaSet)上的服务有了非常灵活的自适应能力,能够在一定限度内复制多个副本来应对某个指标的急剧飙升,也可以在某个指标较小的情况下删除副本来让出计算资源给其他更需要资源的应用使用,维持整个系统的稳定。非常适合于一些流量波动大,机器资源吃紧,服务数量多的业务场景,如:电商服务、抢票服务、金融服务等。
许多监控系统通过adapter实现了接口,给HPA提供指标数据。在这里我们具体介绍一下prometheus监控系统的adapter。
prometheus是一个知名开源监控系统,具有数据维度多,存储高效,使用便捷等特点。用户可以通过丰富的表达式和内置函数,定制自己所需要的监控数据。
prometheus-adapter在prometheus和api-server中起到了适配者的作用。prometheus-adapter接受从HPA中发来,通过apiserver aggregator中转的指标查询请求,然后根据内容发送相应的请求给prometheus拿到指标数据,经过处理后返回给HPA使用。prometheus可以同时实现metrics.k8s.io
、custom.metrics.k8s.io
、 external.metrics.k8s.io
三种api接口,代替k8s自己的matrics-server,提供指标数据服务。prometheus-adapter部署能否成功的关键在于配置文件是否正确。
# 指标规则,可以多个规则共存,上一个规则的结果会传给下一个规则
rules:
# 计算指标数据的表达式
- metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[5m])) by (<<.GroupBy>>)
# 指标重命名,支持正则表达式。这里表示删除指标名字中的"_seconds_total"
name:
as: ""
matches: (.*)_seconds_total$
# 指标与k8s资源通过标签关联,这里将指标通过标签与k8s的namspace和pod相互关联
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
# 过滤指标条件
seriesFilters: []
# 指标查询表达式,可以根据标签等条件,筛选特定的指标
seriesQuery: '{namespace!="",pod!=""}'
v1的模板可能是大家平时见到最多的也是最简单的,v1版本的HPA只支持一种指标 —— CPU。传统意义上,弹性伸缩最少也会支持CPU与Memory两种指标,为什么在Kubernetes中只放开了CPU呢?其实最早的HPA是计划同时支持这两种指标的,但是实际的开发测试中发现,内存不是一个非常好的弹性伸缩判断条件。因为和CPU不同,很多内存型的应用,并不会因为HPA弹出新的容器而带来内存的快速回收,因为很多应用的内存都要交给语言层面的VM进行管理,也就是内存的回收是由VM的GC来决定的。这就有可能因为GC时间的差异导致HPA在不恰当的时间点震荡,因此在v1的版本中,HPA就只支持了CPU一种指标。
StatefulSet是为了解决有状态服务的问题,应用场景包含:稳定的持久化存储(Pod重新调度后还可以访问到相同的持久化数据),稳定的网络标志(Pod重新部署后其Hostname和Podname不会发生变化),有序的删除扩展收缩(Pod是有顺序的,在容器部署或者扩展的时候要依据定义的顺序依次进行,基于init containtor实现)。
DaemonSet确保全部或者一些Node上运行一个Pod副本。当有Node加入集群的时候,会为他们新增一个Pod。当有Node从集群中移除的时候,这些Pod也会被回收。删除DaemonSet将会删除他们创建的所有Pod。典型的应用场景是:每个Node上运行的日志收集、监控、存储客户端等。
Pod内多个容器的网络通信使用lo,各个Pod之间使用Overlay Network,Pod与Service之间使用Iptables规则,在新版本中Pod与Service使用LVS的转发机制。
Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单地说,它的功能是让集群中不同节点的主机创建Docker容器都具有全集群唯一的虚拟IP地址。而且Flannel还可以在这些IP地址之间建立一个覆盖网络,通过这个覆盖网络将数据包原封不动的传递到目标容器内。
HPA与滚动更新的区别:
目前在kubernetes中,可以通过直接管理复制控制器来执行滚动更新,也可以使用deployment对象来管理底层副本集。HPA只支持后一种方法:HPA绑定到部署对象,设置部署对象的大小,部署负责设置底层副本集的大小。
HPA不能使用复制控制器的直接操作进行滚动更新,即不能将HPA绑定到复制控制器并进行滚动更新(例如,使用Kubectl滚动更新)。这不起作用的原因是,当滚动更新创建新的复制控制器时,HPA将不会绑定到新的复制控制器。
Flannel的跨主机通信机制:
在上图中有两个真实的主机,在同一个主机内的Docker容器互相通信通过Docker0网桥即可。但是跨主机通信通过Docker0网桥就无能为力了。当Docker容器启动的时候,Docker0网桥会为其分配一个IP地址,当在宿主机上安装Flanneld的时候会创建Flannel0网桥,Flannel0会监听Docker0的全部数据。当宿主机中的一个Docker向另一个宿主机的Docker容器发起网络请求的时候,数据包会被Flanneld截取,Flanneld将数据包进行封装,发送至另一台主机,另一台主机的Flanneld程序解封装数据包,通过Flannel0网桥和Docker0网桥分发数据到指定的容器。Flanneld封装的数据包如下:
在Kubernetes中的资源实例化后叫做对象。在Kubernetes中的名称空间级别的资源有以下分类:
集群级别的资源有:Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding。
元数据型资源:HPA、PodTemplate、LimitRange。
如下图所示,一个Pod的创建,首先会进行容器环境的初始化,然后创建pause容器,用来共享网络栈和存储卷。然后执行多个initc,初始化容器initc的步骤是串行的。当所有的initc执行完成以后的start部分指的是在容器运行之前的操作,stop部分指的是容器运行结束的操作。在容器整个运行过程中liveness部分用来生存检测。但是在容器的必要条件全局具备的时候还要进行readiness的就绪检测的应用场景就是当一个Pod运行起来的时候,有可能Pod内部的服务还有有全部加载完成,因此需要进行就绪检测。当就绪检测通过的时候再将Pod的运行状态改成RUNNING状态。在Pod的运行过程中,一个极端的情况就是容器内应用剩下的全部都是僵尸进程了,但是表现的来的容器状态还是运行中,因此需要在整个服务的运行周期内都需要进行服务的生存检测。
Init容器与普通的容器相似,但是Init容器总是运行到成功完成为止。每个Init容器都必须在下一个容器启动完成以后运行。如果Pod的容器失败,Kubernetes将会不断的重启该Pod,直到所有的Init容器全部成功运行为止。只有当Pod对应的RestartPoliy为Never的时候才不会重新启动。
Init容器与应用容器分离,因此Init容器可以包含一系列的应用容器运行过程中不需要的实用工具。还可以进行定制化安装,由于Init容器的存在,可以大大降低应用容器的大小。Init容器使用Linux Namespace,所以相对应用程序来说具有不同的文件系统视图,因此它们具备访问Secret的权限,而应用程序的容器则不能。
在所有的Init容器没有成功之前,Pod将不会变成Ready状态,Init容器的端口将不会在Service中聚集。正在初始化中的Pod处于Pending状态,但是会将Initializing状态设置为true。如果Pod重启,所有的Init容器必须重新执行。
Init容器具有应用容器的全部字段,除去就绪检测字段readinessProbe。在Pod中每个app和int的名称必须是唯一的。
虽然initc可以进行就绪探测,但是在initc中进行就绪探测是不太友好的,因为存在initc探测成功但是指定的容器连接目标容器失败的情况,所以最好还是在主容器中进行探测。
探针技术是kubelet对容器执行的定期诊断。kubelet调用容器实现的处理器有三种类型:ExecAction、TCPSocketAction、HTTPGetAction。
对于每次探测,都会出现三种结果:成功、失败和未知。
探测方案存在两种形式:
Pod的状态:
Kubernetes中内建了很多类型的控制器,这些相当于一些状态机,用来控制Pod的具体行为。控制器有以下几种类型:
Service也叫做SVC,用来进行服务发现。SVC中只有一种轮询算法RR,并且只提供四层的负载均衡,无法实现七层负载均衡。
在Kubernetes中SVC有一下四种类型:
ClusterIP:默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP。在同一个Node上的Pod和Node本身可以访问nginx-svc。
在YAML配置文件中指定spec.ports.port和spec.ports.targetPort
NodePort:在ClusterIP基础上为Service在每台机器上绑定端口,这样就可以通过NodeIP:NodePort来访问该服务。
在YAML配置文件中指定spec.ports.port和spec.ports.targetPort以及spec.ports.nodePort,NodePort在30000往上分配。在集群外使用NodePort访问。
在Kubernetes集群中,每个Node运行一个kube-proxy进程。kube-proxy负责为service实现了一种VIP的形式,而不是ExternalName。在Kubernetes v1.0版本中,代理完全在userspace中。在Kubernetes v1.1版本中,新增了iptables代理,但是并不是默认的运行模式。从Kubernetes v1.2开始,默认使用ipatables代理。在Kubernetes v1.8.0-beta0中,添加了ipvs代理。在Kubernetes v1.14版本中,默认使用ipvs代理。在Kubernetes v1.1版本中,新增加了IngressAPI,用来提供七层服务。Kubernetes在历次版本迭代中不使用DNS作为负载均衡的最主要原因是DNS负载均衡方式会在客户端缓存。
IPVS代理模式:这种模式下,kube-proxy会监视Kubernetes的Service对象和Endpoint对象,调用netlink接口来相应的创建ipvs规则并定期与Kubernetes的Service对象和Endpoint对象同步ipvs规则,来确保ipvs状态与期望的一致。访问服务的时候,流量将被重定向到其中一个后端的Pod。与iptables类似,ipvs类似于netfilter的hook功能,但是使用Hash表作为底层数据结构并在内核空间中工作。这意味着ipvs可以更快的进行流量重定向,并且在同步代理规则时具备更好的性能。此外,ipvs为负载均衡算法提供了更多的选项:RR(轮询调度)、LC(最小连接数)、DH(目标Hash)、SH(源Hash)、SED(最短期望延迟)、NQ(不排队调度)。IPVS模式假定在kube-proxy之前的节点上都已经安装了IPVS模块,当kube-proxy以IPVS代理模式启动的时候,kube-proxy将验证节点上是否安装了IPVS模块。如果未安装,则kube-proxy将回退iptables代理模式。
为了实现上面的各种代理模式,api server用户通过kubectl命令向api server发送创建service命令,api server接收到请求将数据存储到etcd中。kube-proxy的每个节点中都有一个叫做kube-proxy的进程,这个进程负责感知service和pod的变化,并将变化的信息写入本地的iptables或者ipvs。使用iptables的NAT等技术或者ipvs将Virtual IP的流量转至Endpoint中。
为了v1.11使用ipvs,需要手动注入两个内核模块变量,否则自动降级到iptables:
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/ipv4/ip_forward
并且:在配置文件/etc/sysconfig/kubelet中添加:
KUBE_PROXY_MODE=ipvs
并且使用modprobe在系统启动时开启如下模块:ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv4
Ingress是一个特殊的调度器,主要是进行SSL会话卸载,支持七层均衡,Service只能发生四层均衡,因此可以在后端的POD上只运行HTTP,外部客户端与Ingress保持HTTPS会话。
Kubernetes的存储主要有:ConfigMap存储、Secret存储、Volume卷存储。
ConfigMap功能在Kubernetes v1.2中版本中引入,许多应用程序会从配置文件、命令行参数和环境变量中读取配置信息。ConfigMap API给我们提供了容器中的注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。
Secret用来存储密码、Token、秘钥等敏感数据的配置问题,Secret可以以Volume或者环境变量的方式使用。Secret有3种类型:
Kubernetes中的卷的生命与它封装的Pod相同。但是卷的生命要比所有容器都长,当容器重新启动的时候,存储在卷中的数据不会丢失。Kubernetes支持多种类型的卷,Pod可以使用任意数量的卷。Kubernetes支持以下类型的卷:
常用的卷存储类型:
PV的出现主要为明确运维工程师和开发工程师的主要任务,PV是Kubernetes提供的抽象存储的概念,但是系统中可能成千上万个PV,因此出现了PVC。PVC会自动匹配PV进行绑定。PV独立于Pod之上。PV分为静态PV和动态PV。静态PV是集群管理员创建的一些PV。当管理员创建的静态PV都不满足用户时,集群可能会动态的尝试为PVC创建卷。PV一旦被绑定,就会具备排他性,PV和PVC一一对应。
PVC保护的目的是确保由Pod正在使用的PVC不会被系统移除。当启用PVC保护的Alpha功能的时候,如果一个用户删除了正在使用的PVC,则这个PVC不会立即删除,而是将会被延迟,直到这个PVC不再被任何Pod使用。
PV是以插件的形式实现的:
PV具备一定的访问模式:
在Kubernetes中回收策略:
目前只有NFS和HostPath支持回收策略,其他仅支持删除策略。
状态:
Scheduler 是Kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。要考虑的问题:
Sheduler 是作为单独的程序运行的,启动之后会一直监听 API Server,获取 PodSpec.NodeName 为空的Pod, 对每个Pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。因为不为空的已经制定了Node节点。
调度分为几个部分:
首先是过滤掉不满足条件的节点,这个过程称为 predicate。
Predicate 有一系列的算法可以使用:
如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序。
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:
通过算法对所有的优先级项目和权重进行计算,得出最终的结果。
除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通过 spec:schedulername 参数指定调度器的名字,可以为 pod 选择某个调度器进行调度。比如下面的 pod 选择 my-scheduler 进行调度,而不是默认的 default-scheduler。
节点亲和性配置:pod.spec.nodeAffinity
POD亲和性配置:pod.spec.affinity.podAffinity/podAntiAffinity
preferredDuringSchedulingIgnoredDuringExecution:软策略
亲和性/反亲和性调度策略比较如下:
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In, NotIn, Exists, DoesNotExist, Gt, Lt | 否 | 指定主机 |
podAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD的同一个拓扑域 |
podAnitAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD不在同 一拓扑域 |
节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点能够 一类特定的 pod。
Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上。
污点 ( Taint ) 的组成:
使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相 斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。
每个污点的组成如下:
key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:
污点的设置、查看和去除:
# 设置污点
kubectl taint nodes node1 key1=value1:NoSchedule
# 节点说明中,查找 Taints 字段 kubectl describe pod pod-name
# 去除污点
kubectl taint nodes node1 key1:NoSchedule-
容忍:
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生 互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容忍 ( Toleration ) ,意思 是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上。
具体的参数:pod.spec.tolerations
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerationSeconds: 3600
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
当不指定 key 值时,表示容忍所有的污点 key:
tolerations:
- operator: "Exists"
当不指定 effect 值时,表示容忍所有的污点作用:
tolerations:
- key: "key"
operator: "Exists"
有多个 Master 存在时,防止资源浪费,可以如下设置:
kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule
指定调度节点:
Pod.spec.nodeName:将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配。
Kubernetes 作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server 是集群内部 各个组件通信的中介,也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计 的。Kubernetes 使用了认证(Authentication)、鉴权(Authorization)、准入控制(Admission Control)三步来保证API Server的安全。
对于认证和鉴权,K8S提供了插件接口来提供认证鉴权的第三方实现,对于认证插件,主要一个插件通过认证和鉴权,则不会尝试其他插件。
三种方式:
两种访问类型:
Kubenetes 组件对 API Server 的访问:kubectl、Controller Manager、Scheduler、kubelet、kube- proxy。Kubernetes 管理的 Pod 对容器的访问:Pod(dashborad 也是以 Pod 形式运行)。
Controller Manager、Scheduler 与 API Server 在同一台机器,所以直接使用 API Server 的非安全端口。访问, --insecure-bind-address=127.0.0.1。kubectl、kubelet、kube-proxy 访问 API Server 就都需要证书进行 HTTPS 双向认证
证书颁发方式:
kubeconfig 文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥),集群 context 信息(集群名称、用户名)。Kubenetes 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群。
Pod中的容器访问API Server。因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。Kubenetes使用了Service Account解决Pod 访问API Server的认证问题。
Secret 与 SA 的关系:Kubernetes 设计了一种资源对象叫做 Secret,分为两类,一种是用于 ServiceAccount 的 service-account- token, 另一种是用于保存用户自定义保密信息的 Opaque。ServiceAccount 中用到包含三个部分:Token、 ca.crt、namespace。
默认将证书和TOKEN存储到/run/secrets/kubernetes.io/serviceaccount
kubectl get secret --all-namespaces
kubectl describe secret default-token-5gm9r --namespace=kube-system
默认情况下,每个 namespace 都会有一个 ServiceAccount,如果 Pod 在创建时没有指定 ServiceAccount, 就会使用 Pod 所属的 namespace 的 ServiceAccount。
上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权 限。API Server 目前支持以下几种授权策略 (通过 API Server 的启动参数 “--authorization-mode” 设置)。
RBAC(Role-Based Access Control)基于角色的访问控制,在 Kubernetes 1.5 中引入,现行版本成为默认标准。相对其它访问控制方式,拥有以下优势:
RBAC:
K8S 1.6之后支持。RBAC 引入了 4 个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4 种对象类型均可以通过 kubectl 与 API 操作。
需要注意的是 Kubenetes 并不会提供用户管理,那么 User、Group、ServiceAccount 指定的用户又是从哪里 来的呢? Kubenetes 组件(kubectl、kube-proxy)或是其他自定义的用户在向 CA 申请证书时,需要提供一个 证书请求文件:
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "CN",
"ST": "HangZhou",
"L": "XS",
"O": "system:masters", "OU": "System"
}]
}
API Server会把客户端证书的 CN 字段作为User,把 names.O 字段作为Group。kubelet 使用 TLS Bootstaping 认证时,API Server 可以使用 Bootstrap Tokens 或者 Token authentication file 验证 =token,无论哪一种,Kubenetes 都会为 token 绑定一个默认的 User 和 Group。
Pod使用 ServiceAccount 认证时,service-account-token 中的 JWT 会保存 User 信息。
有了用户信息,再创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了。
Role and ClusterRole:
在 RBAC API 中,Role 表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过 RBAC 对其进行减少的操作。Role 可以定义在一个 namespace 中,如果想要跨 namespace 则可以创建 ClusterRole。
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole 具有与 Role 相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的,ClusterRole 可以用于:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
RoleBinding and ClusterRoleBinding
RoloBinding 可以将角色中定义的权限授予用户或用户组,RoleBinding 包含一组权限列表(subjects),权限列 表中包含有不同形式的待授予权限资源类型(users, groups, or service accounts);RoloBinding 同样包含对被 Bind 的 Role 引用;RoleBinding 适用于某个命名空间内授权,而 ClusterRoleBinding 适用于集群范围内的授权。
将 default 命名空间的 pod-reader Role 授予 jane 用户,此后 jane 用户在 default 命名空间中将具有 pod- reader 的权限。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
RoleBinding 同样可以引用 ClusterRole 来对当前 namespace 内用户、用户组或 ServiceAccount 进行授权, 这种操作允许集群管理员在整个集群内定义一些通用的 ClusterRole,然后在不同的 namespace 中使用 RoleBinding 来引用。
使用 ClusterRoleBinding 可以对整个集群中的所有命名空间资源权限进行授权。
Kubernetes 集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;同时某些资源也会包含子资源。
RoleBinding 和 ClusterRoleBinding 可以将 Role 绑定到 Subjects;Subjects 可以是 groups、users 或者 service accounts。
Subjects 中 Users 使用字符串表示,它可以是一个普通的名字字符串。也可以是 email 格式的邮箱地址。甚至是一组字符串形式的数字 ID 。但是 Users 的前缀 system: 是系统 保留的,集群管理员应该确保普通用户不会使用这个前缀格式。Groups 书写格式与 Users 相同,都为一个字符串,并且没有特定的格式要求;同样 system: 前缀为系统保留。
准入控制是API Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount。
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的 1.14 的推荐列表是:
NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota。
列举几个插件的功能:
一个YAML文件包括了apiVersion用于说明操作资源的API版本,可以通过kubectl api-versions
查看;kins用于指定内建的资源,包括以下类型:
还有元数据metadata,主要包括以下节点:
最重要的是spec字段,定义了用户的期望状态;status字段定义了初始状态,这个是只读的,用户不能更改。
对于YAML配置文件的说明,可以通过kubectl explain 字段.字段..
查看帮助。
spec字段必须包含containers列表,每个容器的定义包含name和image字段。对于一些容器可能需要指令,那么可以设置command列表。
K8S新一代资源指标架构:
日志收集:
helm 类似于Linux系统下的包管理器,如yum/apt等,可以方便快捷的将之前打包好的yaml文件快速部署进kubernetes内,方便管理维护。
Chart install工作原理:
helm从制定目录或tar文件解析chart结构信息
helm将制定的chart结构和value信息通过gRPC协议传递给tiller
tiller根据chart和values生成一个release
Chart update工作原理:
Chart Rollback工作原理:
Chart处理依赖工作原理:
Tiller 在处理 Chart 时,直接将 Chart 以及其依赖的所有 Charts 合并为一个 Release,同时传递给 Kubernetes。因此 Tiller 并不负责管理依赖之间的启动顺序。Chart 中的应用需要能够自行处理依赖关系。
Chart文件组织:
myapp/ # Chart 目录
├── charts # 这个 charts 依赖的其他 charts,始终被安装
├── Chart.yaml # 描述这个 Chart 的相关信息、包括名字、描述信息、版本等
├── templates # 模板目录
│ ├── deployment.yaml # deployment 控制器的 Go 模板文件
│ ├── _helpers.tpl # 以 _ 开头的文件不会部署到 k8s 上,可用于定制通用信息
│ ├── ingress.yaml # ingress 的模板文件
│ ├── NOTES.txt # Chart 部署到集群后的一些信息,例如:如何使用、列出缺省值
│ ├── service.yaml # service 的 Go 模板文件
│ └── tests
│ └── test-connection.yaml
└── values.yaml # 模板的值文件,这些值会在安装时应用到 GO 模板生成部署文件
name: 由于 DNS 系统的限制,该字段限制为 63 个字符。因此,release 名称限制为 53 个字符。Kubernetes 1.3 及更早版本仅限于 24 个字符(即 14 个字符名称)。