2019-09-04
k8s 相当于就是对 Docker的一层封装,在上面扩展了一些功能。
最好的就是扩容,缩容,设置资源,。。。
1、*组件介绍
点击打开:k8s 结构图
1 | MESOS APACHE 分布式资源管理框架 2019-5 Twitter 》 Kubernetes |
2、基础概念
*pod 概念
pod 是 k8s 最小运行单元。一个 pod 可以有多个容器,多个容器共享 pod的网络,挂载。
所以,一个 pod 不能有端口冲突的容器,否则 pod不能正常启动。
pod 有两种:1、自主式Pod。2、控制器管理的Pod
pod 分类:
1 | + ReplicationController & ReplicaSet & Deployment |
1、ReplicationController < ReplicaSet < Deployment
2、HPA:根据 cpu 自动扩容,缩容
3、StatefulSet:有序(先启动 mysql,再启动 java)
4、运行一个副本节点
5、定时执行、批处理。(感觉没什么用)
网络通讯方式
1、同一 pod 多个容器通讯:同一个pod 内的容器,都是共享同一个网络,所以是 lo 本地回环网络。
2、各pod之间通讯,使用扁平化网络
3、pod 与 service 之间,通过防火墙规则配置
flannel
命令式 VS 声明式
1、命令式(how):给钱 -> 买东西(路应该怎么走,左拐,右拐,。。。)
2、声明式(what):给钱 -> 买东西(无需关心路怎么走)
“命令式”有时也被称作“指令式”,好像有一个是台湾翻译,我不确定是哪一个了。“命令式”强调的是how,如果你是在写命令式的程序,那么你将step-by-step的告诉计算机如何完成一项工作,大多数的程序都是这样的。
在命令式场景下,计算机是不具备“智能”的,只是很机械的完成你交代的事情,至于结果如何,要看你的水平。就像上图,煎饼好吃不好吃、会不会糊锅,要看厨师对原料和火候的掌握。
“声明式”有时也被成为“描述式”或者“申明式”,为告诉计算机你想要什么,“声明”你想要的what,由计算机自己去设计执行路径,需要计算机或者是“运行时”具备一定的“智能”。在这种情况下,计算机显然不会实现所有你想要的what,用专业术语说就是“非图灵完备”,但是针对特定的任务,“声明式”要远比“命令式”方便,其实大多数声明式语言都是针对特定任务的领域专用语言,即DSL。当然,随着深度学习驱动的自动编程技术的兴起,我们有可能在任意领域使用“声明式”完成任务,这是后话,暂且不提。
最常见的声明式语言就是SQL—— 告诉计算机你想要的结果集,SQL语言的运行时,即数据库,帮你设计获取这个结果集的执行路径,并返回结果集。众所周知,使用SQL语言获取数据,要比自行编写处理过程去获取数据容易的多。
3、*集群安装
系统初始化
1 | # 设置系统主机名以及 Host 文件的相互解析 |
Kubeadm 部署安装
1 | # kube-proxy开启ipvs的前置条件 |
4、资源清单:yml 文件
2021-04-09 09:40:21
k8s 中的资源种类
1、什么是资源?
k8s 中所有的内容都抽象为资源,资源实例化之后,叫做对象。
2、k8s 中存在哪些资源?
yml 常用字段
1、必须存在的属性
2、主要对象
3、额外的参数项
*示例:yml 配置
资源清单格式
1 | # 可以使用 kubectl api-versions 获取当前 k8s 版本上所有的 apiVersion 版本信息( 每个版本可能不同 ) |
资源清单的常用命令
获取apiversion
1 | [root@k8s-master01 ~]# kubectl api-versions |
获取资源的apiVersion
1 | [root@k8s-master01 ~]# kubectl explain pod |
获取字段设置帮助文档
1 | [root@k8s-master01 ~]# kubectl explain pod |
字段配置格式
1 | apiVersion <string> #表示字符串类型 |
通过yml文件创建pod
1 | apiVersion: v1 |
*pod 生命周期图示
init 容器
、作为初始化。在真正的容器启动之前启动。启动成功之后,完成工作就销毁。
、只有上一个 init容器工作完成,才能进行下一个 init容器启动。
、真正的 pod处于运行时,init容器是不存在的,真正的容器是存在的。
、一般 init容器用于初始化,和检查。
init 容器:概念
2021-04-12 09:14:45 攀峰说:作为初始化使用,暂时感觉没什么用。
init 容器:作用
init容器:特殊说明
示例:init 容器模版
循环,init容器一直循环,直到有 service(myservice,mydb),才退出循环。
1 | # pod |
1 | # service |
容器探针
探测方式:readinessProbe,livenessProbe
示例:就绪检测:readinessProbe
检测探针 - 就绪检测
1、httpget
1 | apiVersion: v1 |
示例:存活检测:livenessProbe
检测探针 - 存活检测
1、livenessProbe-exec
1 | apiVersion: v1 |
2、livenessProbe-httpget
1 | apiVersion: v1 |
3、livenessProbe-tcp
1 | apiVersion: v1 |
示例:启动/退出、postStart/preStop
1 | apiVersion: v1 |
pod hook(钩子)
*pod 重启策略
*pod phase(生命周期)
1、概念
2、pod phase 存在的可能性
*示例:pod 状态
- Pod 中只有一个容器并且正在运行,容器成功退出
1
2
3
4
5+ 记录事件完成
+ 如果 restartPolicy 为:
+ Always:重启容器;Pod phase 仍为 Running
+ OnFailure:Pod phase 变成 Succeeded
+ Never:Pod phase 变成 Succeeded - Pod 中只有一个容器并且正在运行。容器退出失败
1
2
3
4
5+ 记录失败事件
+ 如果 restartPolicy 为:
+ Always:重启容器;Pod phase 仍为 Running
+ OnFailure:重启容器;Pod phase 仍为 Running
+ Never:Pod phase 变成 Failed - Pod 中有两个容器并且正在运行。容器1退出失败
1
2
3
4
5
6
7
8
9
10
11+ 记录失败事件
+ 如果 restartPolicy 为:
+ Always:重启容器;Pod phase 仍为 Running
+ OnFailure:重启容器;Pod phase 仍为 Running
+ Never:不重启容器;Pod phase 仍为 Running
+ 如果有容器1没有处于运行状态,并且容器2退出:
+ 记录失败事件
+ 如果 restartPolicy 为:
+ Always:重启容器; Pod phase 仍为 Running
+ OnFailure:重启容器; Pod phase 仍为 Running
+ Never:Pod phase 变成 Failed - Pod 中只有一个容器并处于运行状态。容器运行时内存超出限制
1
2
3
4
5
6+ 容器以失败状态终止
+ 记录 OOM 事件
+ 如果 restartPolicy 为 :
+ Always:重启容器;Pod phase 仍为 Running
+ OnFailure:重启容器;Pod phase 仍为 Running
+ Never: 记录失败事件;Pod phase 仍为 Failed - Pod 正在运行,磁盘故障
1
2
3+ 杀掉所有容器。 记录适当事件
+ Pod phase 变成 Failed
+ 如果使用控制器来运行,Pod 将在别处重建 - Pod 正在运行,其节点被分段
1
2
3+ 节点控制器等待直到超时
+ 节点控制器将 Pod phase 设置为 Failed
+ 如果是用控制器来运行,Pod 将在别处重建
5、资源控制器
2021-04-12 10:50:47
*Pod 的分类
- 自主式 Pod:Pod 退出了,此类型的 Pod 不会被创建
- 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
1 | 申明式编程(Deployment) apply(优) create |
简介
什么是控制器?
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为
控制器类型
- ReplicationController(RC) 和 ReplicaSet(RS)
- Deployment
- DaemonSet
- StateFulSet
- Job/CronJob
- Horizontal Pod Autoscaling(HPA)
*rc/rs,ReplicationController/ReplicaSet
ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;
在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟 ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector;
*Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用。
典型的应用场景包括;
- 定义 Deployment 来创建 Pod 和 ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续 Deployment
DaemonSet
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。
当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行 glusterd 、 ceph
- 在每个 Node 上运行日志收集 daemon,例如 fluentd 、 logstash
- 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、 collectd 、Datadog 代理、New Relic 代理,或 Ganglia gmond
*StatefulSet
StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有 Cluster IP的Service)来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到 N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
- 有序收缩,有序删除(即从N-1到0)
Job/CronJob
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。
Cron Job 管理基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 < 1.8,启动 API Server时,通过传递选项 --runtime-config=batch/v2alpha1=true 可以开启 batch/v2alpha1 API
典型的用法如下所示:
- 在给定的时间点调度 Job 运行
- 创建周期性运行的 Job,例如:数据库备份、发送邮件
*HPA,Horizontal Pod Autoscaling
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?
这就有赖于Horizontal Pod Autoscaling(HPA)了,顾名思义,使Pod水平自动缩放(根据 CPU,内存,。。。自动扩容,缩容)
*rc/rs/Deployment 关系
RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数。
即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。
Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector(选择器)
1 | apiVersion: extensions/v1beta1 |
*rs/Deployment 关系
1、会建立一个新的 rs,并在 rs 上创建 3 个 pod。
2、等新的 rs 创建创建,老的 rs 上的 pod 再停止使用。
3、如果要回滚,只需要切换到老的 rs 上面即可。
*Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的 ReplicationController 来方便的管理应用。
典型的应用场景包括:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
示例:部署 Nginx
1 | apiVersion: extensions/v1beta1 |
更新 Deployment
1 | # 修改 nginx pod 镜像: nginx:1.7.9 ===> nginx:1.9.1 |
Deployment 更新策略
Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。
默认的,它会确保至少有比期望的 Pod数量少一个是 up状态(最多一个不可用)
Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。
默认的,它会确保最多比期望的 Pod数量多一个的 Pod 是 up 的(最多1个 surge )
未来的 Kuberentes 版本中,将从1-1变成25%-25%
1 | kubectl describe deployments |
Rollover(多个rollout并行)
假如您创建了一个有5个 niginx:1.7.9
replica的 Deployment,但是当还只有3个 nginx:1.7.9
的 replica 创建出来的时候您就开始更新含有5个 nginx:1.9.1 replica 的 Deployment。
在这种情况下,Deployment 会立即杀掉已创建的3个 nginx:1.7.9
的 Pod,并开始创建 nginx:1.9.1
的 Pod。它不会等到所有的5个 nginx:1.7.9
的 Pod 都创建完成后才开始改变航道
回退 Deployment
1 | kubectl set image deployment/nginx-deployment nginx=nginx:1.91 |
您可以用 kubectl rollout status
命令查看 Deployment 是否完成。如果 rollout 成功完成, kubectl rollout status
将返回一个 0值的 Exit Code
1 | kubectl rollout status deploy/nginx |
回滚历史记录限制
您可以通过设置 .spec.revisonHistoryLimit 项来指定 deployment 最多保留多少 revision 历史记录。
默认的会保留所有的 revision;如果将该项设置为0,Deployment 就不允许回退了。
什么是 DaemonSet
1、DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。
2、当有 Node 加入集群时,也会为他们新增一个 Pod 。
3、当有 Node 从集群移除时,这些 Pod 也会被回收。
4、删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行 glusterd 、 ceph
- 在每个 Node 上运行日志收集 daemon,例如 fluentd 、 logstash
- 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、 collectd 、Datadog 代理、New Relic 代理,或 Ganglia gmond
1 | apiVersion: apps/v1 |
Job/CronJob
Job
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束
特殊说明
- spec.template 格式同Pod
- RestartPolicy仅支持 Never 或 OnFailure
- 单个Pod时,默认Pod成功运行后Job即结束
.spec.completions
标志Job结束需要成功运行的Pod个数,默认为1.spec.parallelism
标志并行运行的Pod的个数,默认为1spec.activeDeadlineSeconds
标志失败Pod的重试最大时间,超过这个时间不会继续重试
Example
1 | apiVersion: batch/v1 |
CronJob Spec
- spec.template格式同Pod
- RestartPolicy仅支持Never或OnFailure
- 单个Pod时,默认Pod成功运行后Job即结束
.spec.completions
标志Job结束需要成功运行的Pod个数,默认为1.spec.parallelism
标志并行运行的Pod的个数,默认为1spec.activeDeadlineSeconds
标志失败Pod的重试最大时间,超过这个时间不会继续重试
CronJob
Cron Job 管理基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
注意:创建 Job 操作应该是 幂等的
使用条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)
典型的用法如下所示:
- 在给定的时间点调度 Job 运行
- 创建周期性运行的 Job,例如:数据库备份、发送邮件
CronJob Spec
.spec.schedule
:调度,必需字段,指定任务运行周期,格式同 Cron.spec.jobTemplate
:Job 模板,必需字段,指定需要运行的任务,格式同 Job.spec.startingDeadlineSeconds
:启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限.spec.concurrencyPolicy
:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。
只允许指定下面策略中的一种:- Allow (默认):允许并发运行 Job
- Forbid :禁止并发运行,如果前一个还没有完成,则直接跳过下一个
- Replace :取消当前正在运行的 Job,用一个新的来替换
注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
.spec.suspend
:挂起,该字段也是可选的。如果设置为 true ,后续所有执行都会被挂起。它对已经开始
执行的 Job 不起作用。默认值为 false 。.spec.successfulJobsHistoryLimit
和.spec.failedJobsHistoryLimit
:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1 。设置限制的值为 0 ,相关类型的 Job 完成后将不会被保留。
Example
1 | apiVersion: batch/v1beta1 |
1 | kubectl get cronjob |
6、Service
2021-04-13 07:56:06
*Service 的概念
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略,通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector。
Service能够提供负载均衡的能力,但是在使用上有以下限制:
- 只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的
Service 的类型
Service 在 k8s 中有以下四种类型
- ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
- NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样外部就可以通过 : NodePort 来访问该服务
- LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort
- ExternalName:(Headless Cluser IP 无头服务)把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持
VIP 和 Service 代理
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。
kube-proxy 负责为 Service 实现了一种VIP(虚拟 virtual IP)的形式,而不是 ExternalName 的形式。
在 Kubernetes v1.0 版本,代理完全在 userspace。
在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。
从 Kubernetes v1.2 起,默认就是iptables 代理。
在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理
在 Kubernetes 1.14 版本开始默认使用 ipvs 代理
在 Kubernetes v1.0 版本, Service 是 “4层”(TCP/UDP over IP)概念。
在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务
!为何不使用 round-robin DNS?
代理模式的分类
1、userspace 代理模式
2、iptables 代理模式
3、ipvs 代理模式
Ⅰ、userspace 代理模式
Ⅱ、iptables 代理模式
Ⅲ、ipvs 代理模式
这种模式,kube-proxy 会监视 Kubernetes Service 对象和 Endpoints ,调用 netlink 接口以相应地创建 ipvs(IP Virtual Server) 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod
与 iptables 类似,ipvs(IP 虚拟服务器) 于 netfilter(网络过滤器) 的 hook(钩子) 功能,但使用哈希表作为底层数据结构并在内核空间中工作。
这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。
此外,ipvs 为负载均衡算法提供了更多选项,例如:
rr
:轮询调度lc
:最小连接数dh
:目标哈希sh
:源哈希sed
:最短期望延迟nq
: 不排队调度
*ClusterIP
clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口
为了实现图上的功能,主要需要以下几个组件的协同工作:
- apiserver 用户通过kubectl命令向 apiserver发送创建 service的命令,apiserver接收到请求后将数据存储到 etcd中
- kube-proxy kubernetes的每个节点中都有一个叫做 kube-porxy的进程,这个进程负责感知 service、pod的变化,并将变化的信息写入本地的 iptables规则中
- iptables 使用 NAT等技术将 virtual IP的流量转至 endpoint中
》》》示例:ClusterIP
1 | # myapp-deploy.yaml |
Headless Service:无头服务
Headless:不在意的;无头脑的;无领导者的;无头的
有时不需要或不想要负载均衡,以及单独的 Service IP 。遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP) 的值为 “None” 来创建 Headless Service 。
这类 Service 并不会分配 Cluster IP, kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由
1 | [root@k8s-master mainfests]# vim myapp-svc-headless.yaml |
*NodePort
nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod
1 | [root@master manifests]# vim myapp-service.yaml |
》》》查询流程
1 | iptables -t nat -nvL KUBE-NODEPORTS |
*LoadBalancer
2021-04-13 08:43:09
负载到不同的 node上。
loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用 cloud provider 去创建 LB 来向节点导流。
ExternalName
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.panfeng.com )。
ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。
相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务
1 | kind: Service |
当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的 DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。
访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发
*Ingress-Nginx
资料信息
Ingress-Nginx github 地址
Ingress-Nginx 官方网站
部署 Ingress-Nginx
1 | kubectl apply -f mandatory.yaml |
*Ingress http代理
》》》deployment、Service、Ingress Yaml 文件
1 | apiVersion: extensions/v1beta1 |
Ingress https代理
- 创建证书,以及 cert 存储方式
1
2
3openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
kubectl create secret tls tls-secret --key tls.key --cert tls.crt - deployment、Service、Ingress Yaml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
spec:
tls:
- hosts:
- foo.bar.com
secretName: tls-secret
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
serviceName: nginx-svc
servicePort: 80
Nginx 进行BasicAuth
访问时,需要认证。(输入账户名,密码)
1 | yum -y install httpd |
1 | apiVersion: extensions/v1beta1 |
Nginx 进行重写
nginx.ingress.kubernetes.io/rewrite-target
:必须重定向流量的目标URI 【串】nginx.ingress.kubernetes.io/ssl-redirect
:指示位置部分是否仅可访问SSL(当Ingress包含证书时默认为True) 【布尔】nginx.ingress.kubernetes.io/force-ssl-redirect
:即使Ingress未启用TLS,也强制重定向到HTTPS 【布尔】nginx.ingress.kubernetes.io/app-root
:定义Controller必须重定向的应用程序根,如果它在’/‘上下文中 【串】nginx.ingress.kubernetes.io/use-regex
:指示Ingress上定义的路径是否使用正则表达式 【布尔】
1 | apiVersion: extensions/v1beta1 |
7、储存
2021-04-14 11:27:22
configMap
configMap 描述信息
ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。
ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象
ConfigMap 的创建
使用目录创建
Ⅰ、使用目录创建
1 | ls docs/user-guide/configmap/kubectl/ |
使用文件创建
Ⅱ、使用文件创建
1 | # 使用文字值创建,利用 —from-literal 参数传递配置信息,该参数可以使用多次 |
pod使用ConfigMap
替代环境变量
Ⅰ、使用 ConfigMap 来替代环境变量
1 | apiVersion: v1 |
1 |
|
1 | apiVersion: v1 |
设置命令行参数
Ⅱ、用 ConfigMap 设置命令行参数
1 | apiVersion: v1 |
1 | apiVersion: v1 |
数据卷地址
Ⅲ、通过数据卷插件使用ConfigMap
1 | apiVersion: v1 |
在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文
件名,键值就是文件内容
1 | apiVersion: v1 |
ConfigMap 的热更新
1 | apiVersion: v1 |
1 | kubectl exec $(kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2) cat /etc/config/log_level |
!!! 更新 ConfigMap 后:
- 使用该 ConfigMap 挂载的 Env 不会同步更新
- 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
Secret
Secret 存在意义
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。
Secret 可以以 Volume 或者环境变量的方式使用。
Secret 有三种类型:
- Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
- Opaque :base64编码格式的Secret,用来存储密码、密钥等
- kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息
Service Account
Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中
1 | kubectl run nginx --image nginx |
Opaque Secret
Opaque Secret:不透明的秘密
Ⅰ、创建说明
Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:
1 | echo -n "admin" | base64 |
secrets.yml
1 | apiVersion: v1 |
Ⅱ、使用方式
1、将 Secret 挂载到 Volume 中
1 | apiVersion: v1 |
2、将 Secret 导出到环境变量中
1 | apiVersion: extensions/v1beta1 |
*dockerConfigJson
使用 Kuberctl 创建 docker registry 认证的 secret
1 | kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER -- docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL |
在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的 myregistrykey
1 | apiVersion: v1 |
volume
*背景
Kubernetes 中的卷有明确的寿命都与封装它的 Pod 相同。所以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。
当然,当 Pod 不再存在时,卷也将不复存在。更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
卷的类型
Kubernetes 支持以下类型的卷:
1 | + awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir |
*emptyDir
当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。
正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。
当出于任何原因从节点中删除 Pod 时, emptyDir 中的数据将被永久删除
emptyDir 的用法有:
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时的检查点
- Web服务器容器提供数据时,保存内容管理器容器提取的文件
1 | apiVersion: v1 |
*hostPath
hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中
hostPath 的用途如下:
- 运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath
- 在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath
- 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在
除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type
使用这种卷类型是请注意,因为:
- 由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同
- 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源
- 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷
1 | apiVersion: v1 |
Persistent Volume
概念
PersistentVolume (PV)
是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。
PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。
此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统
PersistentVolumeClaim (PVC)
是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。
Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)
静态 pv
集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费
动态 pv
当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。
此配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。
声明该类为 “” 可以有效地禁用其动态配置
要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]。
例如,通过确保 DefaultStorageClass 位于 API server 组件的 –admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作
绑定 pv
master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。
如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。
一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。 PVC 跟 PV 绑定是一对一的映射
持久化卷声明的保护
PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失
当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。
PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用
持久化卷类型
PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型:
- GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)
- FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS
- Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
- HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS
持久卷演示代码
1 | apiVersion: v1 |
PV 访问模式
PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。
如下表所示,供应商具有不同的功能,每个PV 的访问模式都将被设置为该卷支持的特定模式。
例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能以只读方式导出到服务器上。
每个 PV 都有一套自己的用来描述特定功能的访问模式
- ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany——该卷可以被多个节点以只读模式挂载
- ReadWriteMany——该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
回收策略
- Retain(保留)——手动回收
- Recycle(回收)——基本擦除( rm -rf /thevolume/* )
- Delete(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除
当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略
状态
卷可以处于以下的某种状态:
- Available(可用)——一块空闲资源还没有被任何声明绑定
- Bound(已绑定)——卷已经被声明绑定
- Released(已释放)——声明被删除,但是资源还未被集群重新声明
- Failed(失败)——该卷的自动回收失败
命令行会显示绑定到 PV 的 PVC 的名称
示例:NFS
持久化演示说明 - NFS
Ⅰ、安装 NFS 服务器
1 | yum install -y nfs-common nfs-utils rpcbind |
Ⅱ、部署 PV
1 | apiVersion: v1 |
Ⅲ、创建服务并使用 PVC
1 | apiVersion: v1 |
*关于 StatefulSet
》陶攀峰:为什么有状态,就是例如:mysql 先启动,再启动 java。先关 java,再关 mysql。
》所以,有状态 StatefulSet,就是为了保证顺序而设计的。
- 匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,web-2
- StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless server name),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化
- StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(service name).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名
- 根据 volumeClaimTemplates,为每个 Pod 创建一个 pvc,pvc 的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Pod name=web-[0-2],因此创建出来的 PVC 是 www-web-0、www-web-1、www-web-2
- 删除 Pod 不会删除其 pvc,手动删除 pvc 将自动释放 pv
Statefulset的启停顺序:
- 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
- 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
- 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。
StatefulSet使用场景:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现。
- 稳定的网络标识符,即 Pod 重新调度后其 PodName 和 HostName 不变。
- 有序部署,有序扩展,基于 init containers 来实现。
- 有序收缩。
8、集群调度
2021-04-15 15:47:08
调度说明
简介
Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。
听起来非常简单,但有很多要考虑的问题:
- 公平:如何保证每个节点都能被分配资源
- 资源高效利用:集群所有资源最大化被使用
- 效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
- 灵活:允许用户根据自己的需求控制调度的逻辑
Sheduler 是作为单独的程序运行的,启动之后会一直坚挺 API Server,获取 PodSpec.NodeName
为空的 pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上
调度过程
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为 predicate
;
然后对通过的节点按照优先级排序,这个是 priority
;
最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误
Predicate 有一系列的算法可以使用:
- PodFitsResources :节点上剩余的资源是否大于 pod 请求的资源
- PodFitsHost :如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
- PodFitsHostPorts :节点上已经使用的 port 是否和 pod 申请的 port 冲突
- PodSelectorMatches :过滤掉和 pod 指定的 label 不匹配的节点
- NoDiskConflict :已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读
如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。
经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程: 按照优先级大小对节点排序
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。
这些优先级选项包括:
- LeastRequestedPriority :通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点
- BalancedResourceAllocation :节点上 CPU 和 Memory 使用率越接近,权重越高。这个应该和上面的一起使用,不应该单独使用
- ImageLocalityPriority :倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高
通过算法对所有的优先级项目和权重进行计算,得出最终的结果
自定义调度器
除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通过 spec:schedulername
参数指定调度器的名字,可以为 pod 选择某个调度器进行调度。
比如下面的 pod 选择 my-scheduler
进行调度,而不是默认的default-scheduler :
1 | apiVersion: v1 |
调度亲和性
2021-04-15 16:06:56
*节点亲和性:软/硬策略
pod.spec.nodeAffinity
- preferredDuringSchedulingIgnoredDuringExecution:软策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.panfeng.com/library/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- qikqiak - requiredDuringSchedulingIgnoredDuringExecution:硬策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.panfeng.com/library/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-node02 - 软策略+硬策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.panfeng.com/library/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-node02
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: source
operator: In
values:
- qikqiak
键值运算关系
- In:label 的值在某个列表中
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
*Pod 亲和性:软/硬策略
pod.spec.affinity.podAffinity/podAntiAffinity
- preferredDuringSchedulingIgnoredDuringExecution:软策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
- 软策略+硬策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31apiVersion: v1
kind: Pod
metadata:
name: pod-3
labels:
app: pod-3
spec:
containers:
- name: pod-3
image: hub.panfeng.com/library/myapp:v1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-1
topologyKey: kubernetes.io/hostname
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-2
topologyKey: kubernetes.io/hostname
亲和性/反亲和性调度策略比较如下:
*污点
2021-04-15 16:30:09
Taint 和 Toleration
Taint:腐坏;污染;污点;感染;难闻的气味
Toleration:宽容,忍受,默认;耐受性
节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点 能够 排斥 一类特定的 pod
Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。
每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。
如果将 toleration 应用于 pod上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上
污点(Taint)
Ⅰ、 污点 ( Taint ) 的组成
使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去
每个污点的组成,例如:key=value:effect
effect:影响;效果;作用
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。
当前 taint effect 支持如下三个选项:
- NoSchedule :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上
- PreferNoSchedule :表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上
- NoExecute :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去
Ⅱ、污点的设置、查看和去除
1 | # 设置污点 |
容忍(Tolerations)
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。
但我们可以在 Pod 上设置容忍 ( Toleration ) ,意思:是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上
pod.spec.tolerations
1 | tolerations: |
其中
- key, vaule, effect 要与 Node 上设置的 taint 保持一致
- operator 的值为 Exists 将会忽略 value 值
- tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Pod 上继续保留运行的时间
Ⅰ、当不指定 key 值时,表示容忍所有的污点 key:
1 | tolerations: |
Ⅱ、当不指定 effect 值时,表示容忍所有的污点作用
1 | tolerations: |
Ⅲ、有多个 Master 存在时,防止资源浪费,可以如下设置
1 | kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule |
*固定节点
2021-04-15 16:40:58
指定调度节点
Ⅰ、Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配
1 | apiVersion: extensions/v1beta1 |
Ⅱ、Pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到目标节点,该匹配规则属于强制约束
1 | apiVersion: extensions/v1beta1 |
9、安全
2021-05-14 16:55:03
机制说明
Kubernetes 作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介,也是外部控制的入口。
所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。
Kubernetes 使用了认证(Authentication)、鉴权(Authorization)、准入控制(AdmissionControl)三步来保证API Server的安全
Authentication
认证流程
认证方式
HTTP Token 认证:通过一个 Token 来识别合法用户
HTTP Token 的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串 - Token 来表达客户的一种方式。
Token 是一个很长的很复杂的字符串,每一个 Token 对应一个用户名存储在 API Server 能访问的文件中。当客户端发起 API 调用请求时,需要在 HTTP Header 里放入 TokenHTTP Base 认证:通过 用户名+密码 的方式认证
用户名+:+密码 用 BASE64 算法进行编码后的字符串放在 HTTP Request 中的 Heather Authorization 域里发送给服务端,服务端收到后进行编码,获取用户名及密码最严格的 HTTPS 证书认证:基于 CA 根证书签名的客户端身份认证方式
Ⅰ、HTTPS 证书认证:
Ⅱ、需要认证的节点
两种类型
- Kubenetes 组件对 API Server 的访问:kubectl、Controller Manager、Scheduler、kubelet、kubeproxy
- 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 双向认证
证书颁发
- 手动签发:通过 k8s 集群的跟 ca 进行签发 HTTPS 证书
- 自动签发:kubelet 首次访问 API Server 时,使用 token 做认证,通过后,Controller Manager 会为kubelet 生成一个证书,以后的访问都是用证书做认证了
Ⅲ、kubeconfig
kubeconfig 文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥),集群 context 信息(集群名称、用户名)。
Kubenetes 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群
Ⅳ、ServiceAccount
Pod中的容器访问API Server。因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。
Kubenetes使用了Service Account解决Pod 访问API Server的认证问题
Ⅴ、Secret 与 SA 的关系
Kubernetes 设计了一种资源对象叫做 Secret,分为两类,一种是用于 ServiceAccount 的 service-accounttoken, 另一种是用于保存用户自定义保密信息的 Opaque。
ServiceAccount 中用到包含三个部分:Token、ca.crt、namespace
、token是使用 API Server 私钥签名的 JWT。用于访问API Server时,Server端认证
、ca.crt,根证书。用于Client端验证API Server发送的证书
、namespace, 标识这个service-account-token的作用域名空间
1 | 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” 设置)
- AlwaysDeny:表示拒绝所有的请求,一般用于测试
- AlwaysAllow:允许接收所有请求,如果集群不需要授权流程,则可以采用该策略
- ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
- Webbook:通过调用外部 REST 服务对用户进行授权
- RBAC(Role-Based Access Control):基于角色的访问控制,现行默认规则
RBAC 授权模式
RBAC(Role-Based Access Control)基于角色的访问控制,在 Kubernetes 1.5 中引入,现行版本成为默认标准。
相对其它访问控制方式,拥有以下优势:
对集群中的资源和非资源均拥有完整的覆盖
整个 RBAC 完全由几个 API 对象完成,同其它 API 对象一样,可以用 kubectl 或 API 进行操作
可以在运行时进行调整,无需重启 API Server
Ⅰ、RBAC 的 API 资源对象说明
RBAC 引入了 4 个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4 种对象类型均可以通过 kubectl 与 API 操作
需要注意的是 Kubenetes 并不会提供用户管理,那么 User、Group、ServiceAccount 指定的用户又是从哪里来的呢?
Kubenetes 组件(kubectl、kube-proxy)或是其他自定义的用户在向 CA 申请证书时,需要提供一个证书请求文件
1 | { |
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
1 | kind: Role |
ClusterRole 具有与 Role 相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的,ClusterRole 可以用于:
- 集群级别的资源控制( 例如 node 访问权限 )
- 非资源型 endpoints( 例如 /healthz 访问 )
- 所有命名空间资源控制(例如 pods )
1 | kind: ClusterRole |
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 的权限。
1 | kind: RoleBinding |
RoleBinding 同样可以引用 ClusterRole 来对当前 namespace 内用户、用户组或 ServiceAccount 进行授权,这种操作允许集群管理员在整个集群内定义一些通用的 ClusterRole,然后在不同的 namespace 中使用RoleBinding 来引用
例如,以下 RoleBinding 引用了一个 ClusterRole,这个 ClusterRole 具有整个集群内对 secrets 的访问权限;
但是其授权用户 dave 只2能访问 development 空间中的 secrets(因为 RoleBinding 定义在 development 命名空间)
1 | # This role binding allows "dave" to read secrets in the "development" namespace. |
使用 ClusterRoleBinding 可以对整个集群中的所有命名空间资源权限进行授权;以下 ClusterRoleBinding 样例展示了授权 manager 组内所有用户在全部命名空间中对 secrets 进行访问
1 | # This cluster role binding allows anyone in the "manager" group to read secrets in any namespace. |
to Resources
Kubernetes 集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;
同时某些资源也会包含子资源,例如 logs 资源就属于 pods 的子资源,API 中 URL 样例如:GET /api/v1/namespaces/{namespace}/pods/{name}/log
如果要在 RBAC 授权模型中控制这些子资源的访问权限,可以通过 / 分隔符来实现,以下是一个定义 pods 资资源 logs 访问权限的 Role 定义样例
1 | kind: Role |
to Subjects
RoleBinding 和 ClusterRoleBinding 可以将 Role 绑定到 Subjects;Subjects 可以是 groups、users 或者 service accounts
Subjects 中 Users 使用字符串表示,它可以是一个普通的名字字符串,如 “alice”;也可以是 email 格式的邮箱地址,如 “1801957499@qq.com”;甚至是一组字符串形式的数字 ID 。
但是 Users 的前缀 system: 是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式。
Groups 书写格式与 Users 相同,都为一个字符串,并且没有特定的格式要求;同样 system: 前缀为系统保留
实践:创建一个用户只能管理 dev 空间
1 | { |
1 | # 下载证书生成工具 |
准入控制
准入控制是API Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的 1.14 的推荐列表是:
- NamespaceLifecycle
- LimitRanger
- ServiceAccount
- DefaultStorageClass
- DefaultTolerationSeconds
- Mutat ingAdmissionWebhook
- ValidatingAdmissionWebhook
- ResourceQuota
列举几个插件的功能:
- NamespaceLifecycle: 防止在不存在的 namespace 上创建对象,防止删除系统预置 namespace,删除namespace 时,连带删除它的所有资源对象。
- LimitRanger:确保请求的资源不会超过资源所在 Namespace 的 LimitRange 的限制。
- ServiceAccount: 实现了自动化添加 ServiceAccount。
- ResourceQuota:确保请求的资源不会超过资源的 ResourceQuota 限制。
10、Helm
2021-05-14 17:40:07
Helm 是什么
在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐,况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂。
helm 通过打包的方式,支持发布的版本管理和控制,很大程度上简化了 Kubernetes 应用的部署和管理。
Helm 本质就是让 K8s 的应用管理(Deployment,Service 等 ) 可配置,能动态生成。通过动态生成 K8s 资源清单文件(deployment.yaml,service.yaml)。
然后调用 Kubectl 自动执行 K8s 资源部署。
Helm 是官方提供的类似于 YUM 的包管理器,是部署环境的流程封装。
Helm 有两个重要的概念:
- chart:是创建一个应用的信息集合,包括各种 Kubernetes 对象的配置模板、参数定义、依赖关系、文档说明等。chart 是应用部署的自包含逻辑单元。可以将 chart 想象成 apt、yum 中的软件安装包
- release:是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release
Helm 包含两个组件:Helm 客户端和 Tiller 服务器,如下图所示
Helm 客户端负责 chart 和 release 的创建和管理以及和 Tiller 的交互。
Tiller 服务器运行在 Kubernetes 集群中,它会处理 Helm 客户端的请求,与 Kubernetes API Server 交互。
Helm 部署
越来越多的公司和团队开始使用 Helm 这个 Kubernetes 的包管理器,我们也将使用 Helm 安装 Kubernetes 的常用 组件。 Helm 由客户端命 helm 令行工具和服务端 tiller 组成,Helm 的安装十分简单。
下载 helm 命令行工具到 master 节点 node1 的 /usr/local/bin
下,这里下载的 2.13.1
版本:
1 | ntpdate ntp1.aliyun.com |
为了安装服务端 tiller,还需要在这台机器上配置好 kubectl 工具和 kubeconfig 文件,确保 kubectl 工具可以在这台机器上访问 apiserver 且正常使用。
这里的 node1 节点以及配置好了 kubectl。
因为 Kubernetes APIServer 开启了 RBAC 访问控制,所以需要创建 tiller 使用的 service account: tiller 并分配合适的角色给它。
详细内容可以查看helm文档中的 Role-based Access Control。 这里简单起见直接分配 cluster- admin 这个集群内置的 ClusterRole 给它。
创建 rbac-config.yaml 文件:
1 | apiVersion: v1 |
1 | kubectl create -f rbac-config.yaml |
tiller
tiller 默认被部署在 k8s 集群中的 kube-system 这个 namespace 下
1 | kubectl get pod -n kube-system -l app=helm |
自定义模板
1 | # 创建文件夹 |
部署 dashboard
kubernetes-dashboard.yaml
1 | cat > kubernetes-dashboard.yaml << 'EOF' |
部署 metrics-server
Heapster GitHub 中已经声明 DEPRECATED 废弃了。
从 Kubernetes 1.12 开始将从 Kubernetes 各种安装脚本中移除。
Kubernetes 推荐使用 metrics-server。
metrics-server.yaml
1 | args: |
1 | helm install stable/metrics-server -n metrics-server --namespace kube-system -f metrics-server.yaml |
部署Prometheus
组件说明
- 1.MetricServer:是kubernetes集群资源使用情况的聚合器,收集数据给kubernetes集群内使用,如kubectl,hpa,scheduler等。
- 2.PrometheusOperator:是一个系统监测和警报工具箱,用来存储监控数据。
- 3.NodeExporter:用于各node的关键度量指标状态数据。
- 4.KubeStateMetrics:收集kubernetes集群内资源对象数 据,制定告警规则。
- 5.Prometheus:采用pull方式收集apiserver,scheduler,controller-manager,kubelet组件数 据,通过http协议传输。
- 6.Grafana:是可视化数据统计和监控平台。
构建记录
1 | git clone https://github.com/coreos/kube-prometheus.git |
修改 grafana-service.yaml 文件,使用 nodepode 方式访问 grafana:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16vim grafana-service.yaml
apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: monitoring
spec:
type: NodePort #添加内容
ports:
- name: http
port: 3000
targetPort: http
nodePort: 30100 #添加内容
selector:
app: grafana修改 prometheus-service.yaml,改为 nodepode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20vim prometheus-service.yaml
apiVersion: v1
kind: Service
metadata:
name: prometheus-k8s
namespace: monitoring
labels:
prometheus: k8s
spec:
type: NodePort
ports:
- name: web
port: 9090
targetPort: web
nodePort: 30200
selector:
app: prometheus
prometheus: k8s修改 alertmanager-service.yaml,改为 nodepode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19vim alertmanager-service.yaml
apiVersion: v1
kind: Service
metadata:
name: alertmanager-main
namespace: monitoring
labels:
alertmanager: main
spec:
type: NodePort
ports:
- name: web
port: 9093
targetPort: web
nodePort: 30300
selector:
alertmanager: main
app: alertmanager
HPA
Horizontal Pod Autoscaling 可以根据 CPU 利用率自动伸缩一个 Replication Controller、Deployment 或者 Replica Set 中的 Pod 数量
1 | kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m --expose --port=80 |
资源限制 - pod
Kubernetes 对资源的限制实际上是通过 cgroup 来控制的,cgroup 是容器的一组用来控制内核如何运行进程的相关属性集合。针对内存、CPU 和各种设备都有对应的 cgroup
默认情况下,Pod 运行没有 CPU 和内存的限额。 这意味着系统中的任何 Pod 将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU 和内存 。
一般会针对某些应用的 pod 资源进行资源限制,这个资源限制是通过resources 的 requests 和 limits 来实现
requests 要分分配的资源,limits 为最高请求的资源值。可以简单理解为初始值和最大值
1 | spec: |
资源限制 - namespace
Ⅰ、计算资源配额
1 | apiVersion: v1 |
Ⅱ、配置对象数量配额限制
1 | apiVersion: v1 |
Ⅲ、配置 CPU 和 内存 LimitRange
、default 即 limit 的值
、defaultRequest 即 request 的值
1 | apiVersion: v1 |
访问 prometheus
prometheus 对应的 nodeport 端口为 30200,访问
http://MasterIP:30200
通过访问
http://MasterIP:30200/target
可以看到 prometheus 已经成功连接上了 k8s 的 apiserver查看 service-discovery
Prometheus 自己的指标
prometheus 的 WEB 界面上提供了基本的查询 K8S 集群中每个 POD 的 CPU 使用情况,查询条件如下:
sum by (pod_name)( rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m] ) )
上述的查询有出现数据,说明 node-exporter 往 prometheus 中写入数据正常,接下来我们就可以部署 grafana 组件,实现更友好的 webui 展示数据了
访问 grafana
查看 grafana 服务暴露的端口号:
1
2kubectl get service -n monitoring | grep grafana
》grafana NodePort 10.107.56.143 <none> 3000:30100/TCP 20h如上可以看到 grafana 的端口号是 30100,浏览器访问
http://MasterIP:30100
用户名密码默认 admin/admin修改密码并登陆
添加数据源 grafana 默认已经添加了 Prometheus 数据源,grafana 支持多种时序数据源,每种数据源都有各自的查询编辑器
Prometheus 数据源的相关参数:
目前官方支持了如下几种数据源:
部署 EFK
Elasticsearch + Filebeat + Kibana
1 | # 添加 Google incubator 仓库 |
11、修改证书时间
2021-05-14 18:43
1 | # 1、go 环境部署 |
12、k8s 高可用集群搭建
系统初始化
1 | # 设置系统主机名以及 Host 文件的相互解析 |
Kubeadm
2021-05-17 10:39:07
1 | # kube-proxy开启ipvs的前置条件 |