https://www.bilibili.com/video/BV1w4411y7Go?p=1
k8s是一个编排容器的工具,其实也是管理应用的全生命周期的一个工具,从创建应用,应用的部署,应用提供服务,扩容缩容应用,应用更新,都非常的方便,而且可以做到故障自愈。
基础设施级服务 iaas :阿里云
平台设施级服务 paas :新浪云
软件设施级服务 saas :Office365
资源管理器:
前生:
Apache:MESOS - 分布式系统内核 、分布式资源管理框架 2019-05 Twitter>k8s
docker:SWARM 集群,轻量 2019-07 阿里云宣布 Docker Swarm集群框架从阿里云选择框架剔除
今世:
google:kubernetes,10年google容器基础框架borg ,容器火了以后,Google使用GO语言参考Borg设计思路开发出K8s
特点:轻量级,基于GO语言,消耗资源小
开源
弹性伸缩
负载均衡:LVS(IPVS)
K8s框架
K8s关键字含义
基础概念 什么是Pod 控制器类型
Pod概念 最小的封装集合,一个Pod会封装多个容器,达到一个子节点的运行环境,K8s管理的最小单位
网络通讯模式
K8s安装:构建K8s集群
资源清单:资源 掌握资源清单的语法 编写Pod 掌握Pod的生命周期***
Pod控制器:掌握各种控制器的特点以及使用定义方式
服务发现:SVC原理及其构建方式
存储:掌握多种存储类型的特点 并且能够在不同环境中选择合适的存储方案(有自己的见解)
服务分类
有状态服务:DBMS
无状态服务:LVS APACHE
高可用集群副本数最好是>=3的奇数
调度器:掌握调度器原理,能够根据要求把Pod定义到想要的节点运行
安全:集群的认证 鉴权 访问控制 原理及其流程 集群安全机制
HELM:类Linux yum 掌握HELM原理 HELM模板自定义 HELM部署一些常用插件
运维:CICD构建 POD特殊的创建管理方式 修改Kubeadm达到证书可用期限10年 构建高可用K8S集群
Borg架构:
K8s架构:
APISERVER:所有服务访问统一入口
CrontrollerManager:维持副本期望数目
Scheduler::负责介绍任务,选择合适的节点进行分配任务
ETCD:键值对数据库 储存K8S集群所有重要信息(持久化),协助分布式集群的正常运转。
Kubelet:直接跟容器引擎交互实现容器的生命周期管理
Kube-proxy:负责写入规则至 IPTABLES、IPVS 实现服务映射访问的
COREDNS:可以为集群中的SVC创建一个域名IP的对应关系解析
DASHBOARD:给 K8S 集群提供一个 B/S 结构访问体系
INGRESS CONTROLLER:官方只能实现四层代理,INGRESS 可以实现七层代理
FEDERATION:提供一个可以跨集群中心多K8S统一管理功能
PROMETHEUS:提供K8S集群的监控能力
ELK:提供 K8S 集群日志统一分析介入平台
推荐在 Kubernetes 集群中使用 Etcd v3,v2 版本已在 Kubernetes v1.11 中弃用
etcd 的官方将它定位成一个可信赖的分布式键值存储服务,它能够为整个分布式集群存储一些关键数据,协助分布式集群的正常运转
Pod类型:
自主式Pod:(不是被控制器管理的Pod):死亡后不会被拉起来,也不会有人创建新的Pod
每个Pod里运行着一个特殊的被称为Pause容器,其他容器为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此他们之间通信和数据交互更为高效。
在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中,同一个Pod里的容器之间仅需通过localhost就能互相通信。
控制器管理的Pod
POD控制器类型:
ReplicationController & ReplicaSet & Deployment
ReplicationController :确保期望值,少了就创建新的Pod替代,多了会自动回收。
新版本的K8S种建议使用ReplicaSet来取代ReplicationControlle,没有本质不同,但只有RS支持集合式的selector(每个Pod有不同标签,RS操作Pod可以按照标签条件操作)
虽然RS可以独立,但是一般还是建议使用Deployment来自动管理RS,这样就无需担心跟其他机制不兼容问题(如RS不支持rolling-update(滚动更新),但是D支持(D本身并不支持Pod创建),所以这俩要一起运行。)
Deployment(ReplicaSet)
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用。典型的应用场景包括:
* 定义 Deployment 来创建 Pod 和 ReplicaSet
* 滚动升级和回滚应用
* 扩容和缩容
* 暂停和继续 Deployment
滚动更新:
更新V1到V2,新建个RS然后创建1个V2,删除1个V1
>直至
达到滚动更新,此时RS,停用、保留,可以回滚>
RS启用,开始回滚老版V1以此类推。
HPA(HorizontalPodAutoScale)根据利用率平滑扩展仅适用于D和RS,在V1版本中支持根据Pod的利用率扩容,在vlalpha版本中,支持根据内存和用户自定义的metric扩缩容。
HPA基于RS定义,并且监控V2Pod的资源利用率
当符合条件后,会创建Pod
每次创建后判断条件,符合后继续创建,直到最大值。使用率小就回收,直到最小值,实现水平自动扩展(弹性伸缩)。
StatefulSet:为了解决有状态服务的问题(Deployment和RS是为了解决无状态服务而设计(Docker主要也是)),其场景包括:
*稳定的持久化存储,即有个Pod死了,重新调度回来以后还是能访问到相同的持久化数据(数据不丢失),基于PVC实现。
*稳定的网络标识,即重新调度后的PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
*有序部署,有序扩展,按照顺序进行M>A>N(从0到N-1,在下一个Pod运行前,之前所有的Pod必须是running和Ready状态),基于init containers来实现。
*有序收缩,有序删除(即从N-1到0) Nagix > Apache >Mysql
DaemonSet:
确保全部(或者一些)Node上 运行一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。除非打污点,正常情况所有Node都会运行一个且只有一个Pod。
典型用法:
*运行集群存储 daemon,例如在每个Node上运行glusterd、ceph
*在每个Node上运行日志收集daemon,例如fluentd、logstash
*在每个Node上运行监控daemon,例如Prometheus Node Exporter、Zabix Agent 都可以封装在DaemonSet中在每个Node上运行,帮我们收集数据。
Job,Cronjob:
job负责批处理任务,即仅执行一次的任务,他保证批处理任务的一个或者多个Pod成功结束。(比如要备份数据库,备份代码可以放到统一Pod里,再放到Job里执行,与Linux直接运行不同点是是封装好的Job可以重复利用,并且脚本执行异常退出可以重复执行,并且可以设置正常退出次数才算Job执行成功)
Cronjob管理基于时间的Job,即
*在给定时间点运行一次
*周期性地在给定时间点运行
服务发现:
Client访问service的IP和端口,使用RR(Round ribbon轮训)等算法间接访问到Pod。
网络通讯模式:
Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中(都可以通过IP直接到达,其实底层有很多转换机制),这在GCE(Google Compute Engine) 里面是现成的网络模型,K8S假定这个网络已存在。而在私有云搭建K8S集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的Docker容器之间互相访问先打通,然后再运行K8S。
同一个Pod内的多个容器间:lo pause
各Pod之间的通讯: Overlay Network
Pod与Service之间的通讯:各节点的Iptables规则,新版本支持LVS 转发上限、效率更高
网络解决方案K8S+Flannel
Flannel是CoreOS团队针对K8S设计的一个网络规划服务,简单来说他,他的功能是让集群中的不同节点主机创建的Docker容器具有全集群唯一的虚拟IP主机。而且它还能在这些IP之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内
ETCD之Flannel提供说明:
>存储管理Flannel可分配的IP地址段资源
>监控ETCD中每个Pod的实际地址,并在内存中建立维护Pod节点路由表
不同情况下网络通信方式
同一个 Pod 内部通讯:同一个 Pod 共享同一个网络命名空间,共享同一个 Linux 协议栈
Pod1 至 Pod2
> Pod1 与 Pod2 不在同一台主机,Pod的地址是与docker0在同一个网段的,但docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间的通信只能通过宿主机的物理网卡进行。将Pod的IP和所在Node的IP关联起来,通过 这个关联让Pod可以互相访问
> Pod1 与 Pod2 在同一台机器,由 Docker0 网桥直接转发请求至 Pod2,不需要经过 Flannel
Pod 至 Service 的网络:目前基于性能考虑,全部为 iptables 维护和转发
Pod 到外网:Pod 向外网发送请求,查找路由表, 转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables执 行Masquerade,把源 IP 更改为宿主网卡的 IP,然后向外网服务器发送请求
外网访问 Pod:Service
组件通讯示意图
K8S构建1台master2台node+Harbor_笔记 :https://www.cnblogs.com/yyq1/p/13991453.html
资源:K8s 中所有的内容都抽象为资源, 资源实例化之后,叫做对象
名称空间级别
工作负载型资源( workload ): Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、 CronJob ( ReplicationController 在 v1.11 版本被废弃 )
服务发现及负载均衡型资源( ServiceDiscovery LoadBalance ): Service、Ingress、…
配置与存储型资源:Volume( 存储卷 )、CSI( 容器存储接口,可以扩展各种各样的第三方存储卷 )
特殊类型的存储卷:ConfigMap( 当配置中心来使用的资源类型 )、Secret(保存敏感数据)、 DownwardAPI(把外部环境中的信息输出给容器)
集群级资源:Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
元数据型资源:(根据某些指标进行操作):HPA、PodTemplate、LimitRange
资源清单含义:
在 k8s 中,一般使用 yaml 格式的文件来创建符合我们预期期望的 pod ,这样的 yaml 文件我们一般 称为资源清单
简单说明
是一个可读性高,用来表达数据序列的格式。YAML 的意思其实是:仍是一种标记语言,但为了强调这种语言以数 据做为中心,而不是以标记语言为重点
基本语法
缩进时不允许使用Tab键,只允许使用空格
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
#标识注释,从这个字符一直到行尾,都会被解释器忽略
YAML 支持的数据结构
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表 (list)
纯量(scalars):单个的、不可再分的值
对象类型:对象的一组键值对,使用冒号结构表示
name: Steve
age: 18
Yaml 也允许另一种写法,将所有键值对写成一个行内对象
hash: { name: Steve, age: 18 }
数组类型:一组连词线开头的行,构成一个数组
animal
- Cat
- Dog
数组也可以采用行内表示法
animal: [Cat, Dog]
复合结构:对象和数组可以结合使用,形成复合结构
1 languages:
2 - Ruby
3 - Perl
4 - Python
5 websites:
6 YAML: yaml.org
7 Ruby: ruby-lang.org
8 Python: python.org
9 Perl: use.perl.org
纯量:纯量是最基本的、不可再分的值。以下数据类型都属于纯量
1 字符串 布尔值 整数 浮点数 Null
2 时间 日期
数值直接以字面量的形式表示
number: 12.30
布尔值用true和false表示
isSet: true
null用 ~ 表示
parent: ~
时间采用 ISO8601 格式
iso8601: 2001-12-14t21:59:43.10-05:00
日期采用复合 iso8601 格式的年、月、日表示
date: 1976-07-31
YAML 允许使用两个感叹号,强制转换数据类型
e: !!str 123
f: !!str true
字符串
字符串默认不使用引号表示
str: 这是一行字符串
如果字符串之中包含空格或特殊字符,需要放在引号之中
str: '内容: 字符串'
单引号和双引号都可以使用,双引号不会对特殊字符转义
s1: '内容\n字符串'
s2: "内容\n字符串"
单引号之中如果还有单引号,必须连续使用两个单引号转义
str: 'labor''s day'
字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为 空格
str: 这是一段
多行
字符串
多行字符串可以使用|保留换行符,也可以使用>折叠换行
this:|
Foo
Bar
that: >
Foo
Bar
+ 表示保留文字块末尾的换行,- 表示删除字符串末尾的换行
s1: |
Foo
s2: |+
Foo
s3: |-
Foo
参考资料: https://www.cnblogs.com/panwenbin-logs/p/9895953.html
必须存在的属性:
主要对象:
额外的参数项:
kubectl explain pod
查看pod模板
继续查看
kubectl explain pod.spec
kubectl explain pod.spec.containers
创建一个简单的yaml模板
vi pod.yaml
这里使用相同镜像,默认情况会端口冲突
使用yaml文件创建pod:
kubectl apply -f pod.yaml
已经创建
查看运行情况
发现容器报错,不断重启,已经重启4次了
排查问题:
kubectl describe pod mynginx-pod
第二个 test容器报错了
查看test容器
kubectl log mynginx-pod -c test
kubectl logs mynginx-pod -c test
指定查看pod和容器日志
80端口被占用
删除 test容器:
vim pod.yaml
kubectl delete pod mynginx-pod
kubectl get pod
kubectl apply -f pod.yaml
kubectl get pod
Init 容器
Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器
Init 容器与普通的容器非常像,除了如下两点:
Ø Init 容器总是运行到成功完成为止
Ø 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,
如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动
Init 容器的作用
因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:
Ø 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这 些实用工具的
Ø 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建 镜像没必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具。
Ø 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
Ø Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因 此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
Ø 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容 器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
Init 容器
init 模板
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
检测探针 - 就绪检测
readinessProbe-httpget
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
spec:
containers:
检测探针 - 存活检测
livenessProbe-exec
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
livenessProbe-httpget
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
livenessProbe-tcp
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
启动、退出动作
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
开始测试:
在节点执行
docker pull busybox
vim init.pod.yaml
kubectl create -f init.pod.yaml
如果遇到重名,删除操作:
kubectl get pod
kubectl delete deployment --all
kubectl get pod
kubectl delete pod --all
kubectl get pod
kubectl get svc
kubectl delete svc nginx-deployment
kubectl get svc
kubectl create -f init.pod.yaml
状态没有ready
kubectl describe pod myapp-pod
kubectl log myapp-pod -c init-myservice
一直没解析到 myservice
创建 myservice
vim myservice.yaml
kubectl log myapp-pod -c init-myservice
等待后
kubectl get pod
已经成功了1个
发现已经创建了myservice的svc
这个svc会被集群内部的dns解析
创建pod时指定了myservice的svc,创建svc后会写入到coredns,pod请求core会返回请求,至此按照pod yaml的配置已经过去了第一个myservice,还剩一个mydb。
创建mydb
vim mydb.yaml
kubectl create -f mydb.yaml
成功启来了
只有所有init c成功运行后 ,main c才会被运行。
如果报错
kubectl describe pod myapp-pod
原因为node1下载busybox失败,可能原因为 不指定版本号,会使用latest标签保存,每次使用都会去下载最新版,下载失败就会报错。
特殊说明 -1
在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个 容器启动之前成功退出
如果由于运行时或失败退出,将导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略 进行重试。然而,如果 Pod 的 restartPolicy 设置为 Always,Init 容器失败时会使用 RestartPolicy 策略
在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 Pending 状态,但应该会将 Initializing 状 态设置为 true
如果 Pod 重启,所有 Init 容器必须重新执行
# 对 Init 容器 spec 的修改被限制在容器 image 字段,修改其他字段都不会生效。更改 Init 容器的 image 字段,等价于重启该 Pod
Init 容器具有应用容器的所有字段。除了 readinessProbe,因为 Init 容器无法定义不同于完成 (completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行
在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证 时抛出错误
容器探针
探针是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三 种类型的处理程序:
ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断 被认为是成功的。
HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的 状态码大于等于200 且小于 400,则诊断被认为是成功的
每次探测都将获得以下三种结果之一:
成功:容器通过了诊断。
失败:容器未通过诊断。
未知:诊断失败,因此不会采取任何行动
探测方式
livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将 受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success
readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的 所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容 器不提供就绪探针,则默认状态为 Success
检测探针 - 就绪检测(符合条件才READY状态) 测试:
readinessProbe-httpget 方案
vim read.yaml
kubectl create -f read.yaml
kubectl get pod
虽然显示Running 但是没有READY查看日志
kubectl describe pod readiness-httpget-pod
没有找到index1.html 报404页面不存在,原因为yaml文件里检测的index1.html ,真实不存在
进入容器 readiness-httpget-pod
kubectl exec readiness-httpget-pod -it -- /bin/sh
cd /usr/share/nginx/html
echo "123" > index1.html
exit
kubectl get pod
因为文件已经存在,检测到就READY了,测试完毕,删除:
kubectl delete pod --all
kubectl delete svc mydb myservice
检测探针 - 存活检测(不符合条件就重启) 测试:
livenessProbe-exec方案
vim live-exec.yaml
kubectl create -f live-exec.yaml
等待一分钟
重启原因为yaml文件设置如果文件不存在,存活检测会重启Pod,达到60秒(排除启动和延迟,实际要多一点)重启的结果。清理:
kubectl delete pod --all
livenessProbe-httpget方案
vim live.http.yaml
kubectl create -f live.http.yaml
kubectl get pod
正常启动
可以访问
删除index.html
kubectl exec liveness-httpget-pod -it -- /bin/sh
exit
curl 10.244.2.9/index.html
报错404
kubectl get pod
由于yaml文件中设置了检测index.html是否存在,如果不存在就重启, 查看重启次数已经是1了。
由于重启后index.html又回来, 之后就没有重启。
再删一次:
由于设置的是3秒检测一次,很快就又重启了。
清理:
kubectl delete pod --all
livenessProbe-tcp方案
vim live-tcp.yaml
kubectl create -f live-tcp.yaml
kubectl get pod -w
由于检测的端口是8080,nginx端口是80,初始5秒后开始检测,发现没有8080,1秒后重启。
合并检测方式:
vim live-http.yaml
同时进行 readinessProbe(就绪检测) 和livenessProbe(存活检测)
发现由于没有index1.html 一直没ready
kubectl exec liveness-httpget-pod -it -- /bin/bash
echo "123" >> /usr/share/nginx/html/index1.html
exit
kubectl get pod
发现已经就绪了
继续测试 存活检测:
kubectl exec liveness-httpget-pod -it -- rm -rf /usr/share/nginx/html/index.html
kubectl get pod -w
发现删除后就重启,并且由于重启后又没有index1.html,就绪检测执行后未通过。
readinessProbe(就绪检测) 和livenessProbe(存活检测)可以配合init c start stop 使用
了解 start stop
vim post.yaml
kubectl create -f post.yaml
kubectl exec lifecycle-demo -it -- cat /usr/share/message
验证通过
此不会采取任何行动
Pod hook
Pod hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进 程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook
Hook 的类型包括两种:
exec:执行一段命令
HTTP:发送HTTP请求
重启策略
PodSpec 中有一个 restartPolicy 字段,可能的值为 Always、OnFailure 和 Never。默认为 Always。 restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅指通过同一节点上的 kubelet 重新启动容器。失败的容器由 kubelet 以五分钟为上限的指数退避延迟(10秒,20秒,40 秒…)重新启动,并在成功执行十分钟后重置。如 Pod 文档 中所述,一旦绑定到一个节点,Pod 将 永远不会重新绑定到另一个节点。
Pod phase
Pod 的 status 字段是一个 PodStatus 对象,PodStatus中有一个 phase 字段。
Pod 的相位(phase)是 Pod 在其生命周期中的简单宏观概述。该阶段并不是对容器或 Pod 的综合汇 总,也不是为了做为综合状态机
Pod 相位的数量和含义是严格指定的。除了本文档中列举的状态外,不应该再假定 Pod 有其他的 phase 值
Pod phase 可能存在的值
挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间 包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间
运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容 器正在运行,或者正处于启动或重启状态
成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启
失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容 器以非 0 状态退出或者被系统终止
未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败
Pod 的分类
自主式 Pod:Pod 退出了,此类型的 Pod 不会被创建
控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
什么是控制器
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为
控制器类型
ReplicationController 和 ReplicaSet (无状态服务RS-Deployment)
Deployment
DaemonSet(以Node为节点部署)
StateFulSet (有状态服务)
Job/CronJob (批处理任务部署)
Horizontal Pod Autoscaling (可以理解为并不是一个控制器,而是一个控制器的附属品,以其他控制器作为模板)
ReplicationController 和 ReplicaSet
ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;
在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector;
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括;
定义 Deployment 来创建 Pod 和 ReplicaSet
滚动升级和回滚应用
扩容和缩容
暂停和继续 Deployment
命令式编程:它侧重于如何实现程序,就像编程那样,把步骤一步步写下来。
声明式编程:它侧重定义想要什么,然后告诉计算机/引擎,让他帮你去实现。
声明式编程 (Deployment) apply(优) create
命令式 (rs) create(优) apply
Deployment创建rs,rs创建、管理pod
DaemonSet
DaemonSet 确保全部(或者一些,根据调度策略或者污点定义)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod使用 DaemonSet 的一些典型用法:
运行集群存储 daemon,例如在每个 Node 上运行 glusterd 、 ceph
在每个 Node 上运行日志收集 daemon,例如 fluentd 、 logstash
在每个 Node 上运行监控 daemon,例如 zabbix agent、Prometheus Node Exporter、 collectd 、Datadog 代理、New Relic 代理,或 Ganglia gmond
Job
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束(跟linux crontab比有纠错功能)
CronJob (在特定的时间循环创建Job)
Cron Job 管理基于时间的 Job,即: 分时日月周
在给定时间点只运行一次
周期性地在给定时间点运行
使用前提条件:**当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 <1.8,启动 API Server时,通过传递选项 --runtime-config=batch/v2alpha1=true 可以开启 batch/v2alpha1API**
典型的用法如下所示:
在给定的时间点调度 Job 运行
创建周期性运行的 Job,例如:数据库备份、发送邮件
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)
Horizontal Pod Autoscaling
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放
[root@k8s-master01 ~]# kubectl explain rs
RS 与 RC 与 Deployment 关联
RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 。即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收
Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector
[root@k8s-master01 ~]# vim rs.yaml
kubectl create -f rs.yaml
kubectl get pod
多出了3个Pod
kubectl delete pod --all
清理以前的Pod
kubectl get pod
之前4个pod全被删除,没有删除deployment,为了维持定义的副本数又创建了3个pod,但是名称不一样了。
查看标签
kubectl get pod --show-labels
yaml文件中定义的标签是 frontend
更改标签
报错,提示frontend-bdhhj已有标签,除非添加--overwrite参数
kubectl label pod frontend-bdhhj tier=frontend1 --overwrite=True
提示已修改,可以看到frontend-bdhhj标签已改,并且由于yaml模板中pod设置了匹配标签选项,frontend标签继续保持副本数添加了一个新的pod。
删除rs
kubectl delete rs --all
kubectl get pod --show-labels
仅删除了rs关联的pod
清理
kubectl delete pod --all
RS 与 Deployment 的关联
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:
定义Deployment来创建Pod和ReplicaSet
滚动升级和回滚应用
扩容和缩容
暂停和继续Deployment
I、部署一个简单的 Nginx 应用
vim deployment.yaml
kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record
## --record参数可以记录命令,我们可以很方便的查看每次 revision 的变化
kubectl get deployment
kubectl get rs
kubectl get pod
deployment创建会创建对应的rs
访问
curl 10.244.1.16
II、扩容副本数
kubectl scale deployment nginx-deployment --replicas=10
发现像nginx这种无状态服务扩容特别简单
名称未变,数目调整不会调整模板信息
III、更新镜像:
kubectl set image deployment/nginx-deployment nginx=hub.yyq.com/library/mynginx:v2
提示已更新
查看rs
kubectl get rs
发现 期望是2 当前是2 但是ready是0
查看Pod
发现当前并没有v2版本,也就pull不到
创建一个v2
cd n/
vim Dockerfile
#Version:2
FROM hub.yyq.com/library/mynginx:v1
RUN echo $HOSTNAME > /usr/share/nginx/html/index.html
docker build -t="hub.yyq.com/library/mynginx:v2" .
docker login https://hub.yyq.com
docker push hub.yyq.com/library/mynginx:v2
kubectl delete deployment nginx-deployment
kubectl create -f deployment.yaml
kubectl scale deployment nginx-deployment --replicas=10
kubectl set image deployment/nginx-deployment nginx=hub.yyq.com/library/mynginx:v2
kubectl get pod -o wide -w
过程如:
陆续更新完成
kubectl get rs
已全部更新
验证
IV、回滚:
kubectl rollout undo deployment/nginx-deployment
交替过程
kubectget pod -w -o wide
kubectl rollout status deployment/nginx-deployment
kubect get rs
验证
kubectl rollout status deployment/nginx-deployment
curl 10.244.2.64
回v1版了
V、如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展
kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
可以使用 edit 命令来编辑 Deployment
kubectl edit deployment/nginx-deployment
deployment "nginx-deployment" edited
可以更新副本数或其他
Deployment 更新策略
Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)
Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望的Pod数量多一个的 Pod 是 up 的(最多1个 surge )
未来的 Kuberentes 版本中,将从1-1变成25%-25% (无论数量多少,交替过程中每次操作25%的数量)
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
kubectl set image deployment/nginx-deployment nginx=nginx:1.91
kubectl rollout status deployments nginx-deployment
kubectl get pods
kubectl rollout history deployment/nginx-deployment
CHANGE-CAUSE 是none 因为创建时没有加--record
测试一下:
kubectl delete deployment --all
kubectl create -f deployment.yaal --record
kubectl set image deployment/nginx-deployment nginx=hub.yyq.com/library/mynginx:v2
kubectl rollout history deployment/nginx-deployment
kubectl set image deployment/nginx-deployment nginx=hub.yyq.com/library/mynginx:v3
kubectl rollout history deployment/nginx-deployment
kubectl get rs
产生了新的rs
kubectl rollout undo deployment/nginx-deployment --to-revision=1
## 可以使用 --revision参数指定某个历史版本
再看历史版本
kubectl rollout history deployment/nginx-deployment
当前版本的这里查看历史版本,回退到以前的版本时以前的版本号会变成新的号,比如按照上图回退到2,就会变成3 4 5,再会退到4就变成356
kubectl rollout pause deployment/nginx-deployment
## 暂停 deployment 的更新
您可以用 kubectl rollout status 命令查看 Deployment 是否完成。如果 rollout 成功完成, kubectl rollout
status 将返回一个0值的 Exit Code
kubectl rollout status deploy/nginx
Waiting for rollout to finish: 2 of 3 updated replicas are available…
deployment "nginx" successfully rolled out
$ echo $?
0
kubectl delete deployment --all
清理 Policy
您可以通过设置 .spec.revisonHistoryLimit 项来指定 deployment 最多保留多少 revision 历史记录。默认的会
保留所有的 revision;如果将该项设置为0,Deployment 就不允许回退了
什么是 DaemonSet
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
使用 DaemonSet 的一些典型用法:
运行集群存储 daemon,例如在每个 Node 上运行 glusterd 、 ceph
在每个 Node 上运行日志收集 daemon,例如 fluentd 、 logstash
在每个 Node 上运行监控 daemon,例如 Zabbix agent、 Prometheus Node Exporter、 collectd 、Datadog 代理、New Relic 代理,或 Ganglia gmond
vim daemonset.yaml
kubectl create -f daemonset.yaml
kubect get pod
kubectl get daemonset.apps
kubectl get pod
Job
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束
特殊说明
spec.template格式同Pod
RestartPolicy仅支持Never或OnFailure
单个Pod时,默认Pod成功运行后Job即结束
.spec.completions 标志Job结束需要成功运行的Pod个数,默认为1
.spec.parallelism 标志并行运行的Pod的个数,默认为1
spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试
vim job.yam
计算Pi2000位(根据机器性能可以调小点)
kubectl create -f job.yaml
kubectl get pod
kubectl describe pod pi-lbrh5
正在下镜像,太慢了,手动导入
yum -y install lrzsz
perl.tar.gz
[root@k8s-master01 ~]# tar xvf perl.tar.gz
[root@k8s-master01 ~]# docker load -i perl.tar
[root@k8s-master01 ~]# scp perl.tar root@k8s-node01:/root
[root@k8s-master01 ~]# scp perl.tar root@k8s-node02:/root
[root@k8s-node01 ~]# docker load -i perl.tar
[root@k8s-node02 ~]# docker load -i perl.tar
kubectl get pod
时间比较久,已经ImagePullBackOff了,删除,自己重建。
kubectl get pod -o wide
等待
kubectl get pod
已经Completed了
get pod job
作业完成
查看日志
已经将圆周率推算到2000位,如果运行太慢,修改yaml文件将数字改小,删除后然后重新创建。
CronJob Spec
spec.template格式同Pod
RestartPolicy仅支持Never或OnFailure
单个Pod时,默认Pod成功运行后Job即结束
.spec.completions 标志Job结束需要成功运行的Pod个数,默认为1
.spec.parallelism 标志并行运行的Pod的个数,默认为1
spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试
CronJob
Cron 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 完成后将不会被保留。
vim cronjob.yaml
kubectl apply -f cronjob.yaml
kubectl get cronjob
kubectl get job
kubectl log hello-1605656340-gbf95
清理
kubectl delete cronjob --all
pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath={.items..metadata.name})
CrondJob 本身的一些限制
创建 Job 操作应该是 幂等 的
Service 的概念
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector
这里的分配机制只有RR轮训
Service能够提供负载均衡的能力,但是在使用上有以下限制:
只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的
Service 的类型
Service 在 K8s 中有以下四种类型
ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 : NodePort 来访问该服务
LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort
需要借助于供应商来保存注册、端口等信息,需要单独收费
ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes1.7 或更高版本的 kube-dns 才支持
VIP 和 Service 代理
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。 kube-proxy 负责为 Service 实现了一种VIP(虚拟 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?
解析在客户端缓存,很多客户端解析后不会及时清理,可能会造成无法及时更新。
代理模式的分类
I、userspace 代理模式
II、iptables 代理模式
III、ipvs 代理模式
这种模式,kube-proxy 会监视 Kubernetes Service 对象和 Endpoints ,调用 netlink 接口以相应地创建ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod
与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:
rr :轮询调度
lc :最小连接数
dh :目标哈希
sh :源哈希
sed :最短期望延迟
nq : 不排队调度
ClusterIP
clusterIP 主要在每个 node 节点使用 iptables(或ipvs),将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口
为了实现图上的功能,主要需要以下几个组件的协同工作:
apiserver 用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中
kube-proxy kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中
iptables 使用NAT等技术将virtualIP的流量转至endpoint中
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.25.0/deploy/static/mandatory.yaml
由于镜像获取问题Service后续测试无法验证。
delete deployment --all
delete ingress --all
delete svc svc-1 svc-2 svc-3
7.1configMap(存储配置文件)
7.2Secret(加密信息)
7.3volume(共享存储卷)
7.4Persistent Volume(PV、PVC 持久卷)
configMap 描述信息
ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON二进制大对象
ConfigMap 的创建
I、使用目录创建
mkdir configmap
cd configmap/
mkdir dir
cd dir/
vim game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
vim ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kubectl create configmap game-config --from-file=/root/configmap/dir/
—from-file 指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl get cm
kubectl get cm game-config -o yaml
可以看到设置的值信息
kubectl describe cm game-config
也可以看到
II、使用文件创建
只要指定为一个文件就可以从单个文件中创建 ConfigMap
kubectl create configmap game-config-2 --from-file=/root/configmap/dir/game.properties
—from-file 这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的
kubectl get configmaps game-config-2 -o yaml
III、使用字面值创建
使用文字值创建,利用 —from-literal 参数传递配置信息,该参数可以使用多次,格式如下
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
kubectl get configmaps special-config -o yaml
kubectl describe configmap special-config
Pod 中使用 ConfigMap
I、使用 ConfigMap 来替代环境变量
已有
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
mkdir mkdir /root/configmap/env/
cd mkdir /root/configmap/env/
vim env.yaml
kubectl get cm
vim pod.yaml
kubectl get pod
由于yaml设置的command执行成功后状态就完成了
kubectl log dapi-test-pod
II、用 ConfigMap 设置命令行参数
已有
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
vim pod1.yaml
kubectl create -f pod1.yaml
kubectl get pod
kubectl log dapi-test-pod66
command 中的$(SPECIAL_LEVEL_KEY) 对应的 special-config中的special.how设置的的very charm
III、通过数据卷插件使用ConfigMap
已有
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
vim 111.yaml
kubectl create -f 111.yaml
kubectl get pod
kubectl log dapi-test-pod11
报错
修改yaml
vim 111.yaml
command: [ "/bin/sh", "-c", "sleep 600s" ]
delete -f 111.yaml
kubectl create -f 111.yaml
kubectl get pod
kubectl exec dapi-test-pod11 -it -- /bin/sh
cd /etc/config
ls
cat special.how
volumes挂载成功
清理
kubectl delete pod --all
kubectl delete cm --all
ConfigMap 的热更新
mkdir /root/configmap/config
cd /root/configmap/config
vim 111.yaml
kubectl apply -f 111.yaml
kubectl get pod
kubectl exec my-nginx-64b66b49d8-rz6bc -it -- cat /etc/config/log_level
验证完成
热更新
修改 ConfigMap
kubectl edit configmap log-config
修改 log_level 的值为 DEBUG 等待大概 10 秒钟时间,再次查看环境变量的值
kubectl exec my-nginx-64b66b49d8-rz6bc -it -- cat /etc/config/log_level
再次执行,发现已经改过来了。
ConfigMap 更新后滚动更新 Pod
更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新
kubectl patch deployment my-nginx --patch '{"spec": {"template": {"metadata": {"annotations":{"version/config": "20190411" }}}}}'
这个例子里我们在 .spec.template.metadata.annotations 中添加 version/config ,每次通过修改version/config 来触发滚动更新
!!! 更新 ConfigMap 后:
使用该 ConfigMap 挂载的 Env 不会同步更新
使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
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 目录中
kubectl get pod
kubectl exec my-nginx-64b66b49d8-rz6bc -it -- /bin/sh
cd /run/secrets/kubernetes.io/serviceaccount
ls
ca.crt
namespace #pod所在namespace
token #认证信息
Opaque Secret
I、创建说明
Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:
echo -n "admin" | base64
YWRtaW4=
echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
[root@k8s-master01 config]# vim secrets.yml
kubectl apply -f secrets.yml
kubectl get secrets
已创建,并且每个名称空间下都会有一个默认的token,用于pod的挂载。
kubectl get secrets -n kube-system
II、使用方式
1、将 Secret 挂载到 Volume 中
[root@k8s-master01 config]# vim pod1.yaml
kubectl apply -f pod1.yaml
kubectl get pod
kubectl exec seret-test -it -- /bin/sh
cat /erc/secrets/username
已经被解密
清理
kubectl delete pod --all
2、将 Secret 导出到环境变量中
[root@k8s-master01 config]# vim env.yaml
kubectl apply -f env.yaml
kubectl exec pod-deployment-564f59b6b7-6q5zg -it -- /bin/sh
测试通过
清理
kubectl delete -f env.yaml
kubectl delete deployment --all
kubernetes.io/dockerconfigjson
kubernetes.io/dockerconfigjson
使用 Kuberctl 创建 docker registry 认证的 secret
模拟K8s启动时候提示无法pull镜像的场景,然后用认证解决,首先把仓库设置成私有。
每台都删除之前的镜像
docker rmi hub.yyq.com/library/mynginx:v1
每台都退出登录
docker logout hub.yyq.com
mkdir reg
cd reg
vim pod.yaml
kubectl create -f pod.yaml
kubectl get pod
报错,查看日志
kubectl describe pod foo
无法pull镜像,必须要认证以后才能下载
通过dockerconfigjson解决
kubectl create secret docker-registry myregistrykey --docker-server=hub.yyq.com --docker-username=admin --docker-password=Harbor12345 --docker-email=13439629295@139.com
secret 创建成功
编辑yaml文件,添加
vim pod.yaml
imagePullSecrets:
kubectl delete -f
kubectl create -f pod.yaml
kubectl get pod
kubectl describe pod foo
pull成功
清理
kubectl delete pod --all
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解决了这些问题
背景
Kubernetes 中的有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
卷的类型
Kubernetes 支持以下类型的卷:
awsElasticBlockStore
azureDisk
azureFile
cephfs
csi
downwardAPI
emptyDir
fc
flocker
gcePersistentDisk
gitRepo
glusterfs
hostPath
iscsi
local
nfs
persistentVolumeClaim
projected
portworxVolume
quobyte
rbd
scaleIO
secret
storageos
vsphereVolume
emptyDir
当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时, emptyDir 中的数据将被永久删除
<--注意:容器崩溃不会从节点中移除 pod,因此 ·emptyDir· 卷中的数据在容器崩溃时是安全的-->
emptyDir 的用法有:
暂存空间,例如用于基于磁盘的合并排序
用作长时间计算崩溃恢复时的检查点
Web服务器容器提供数据时,保存内容管理器容器提取的文件
[root@k8s-master01 reg]# ntpdate ntp1.aliyun.com
mkdir volume
cd volume
vim em.yaml
kubectl apply -f em.yaml
kubectl exec test-pd -it -- /bin/sh
修改yaml,再添加一个容器
vim em.yaml
kubectl create -f em.yaml
kubectl exec test-pd1 -c test-container -it -- /bin/sh
使用另外一个终端登录另外一个容器
有index.html,继续测
返回另外一个容器
同步了
清理
kubectl delete pod --all
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 卷
vim pod1.yaml
在node01 node02上创建文件
mkdir /data
kubectl create -f pod1.yaml
kubectl exec test-pd -it -- /bin/sh
在node02上查看 /data
在node上重新写入
查看容器
同步了
概念
PersistentVolume (PV)
是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统
PersistentVolumeClaim (PVC)
是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)
静态 pv
集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费
动态
当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为 "" 可以有效地禁用其动态配置
要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]。例如,通过确保 DefaultStorageClass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作
绑定
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
持久卷演示代码
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
PV 访问模式
PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV 的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式
ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
ReadOnlyMany——该卷可以被多个节点以只读模式挂载
ReadWriteMany——该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
Volume 插件
回收策略
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
I、安装 NFS 服务器
在Harbor上部署NFS:
Harbor启动:
docker-compose start
yum install -y nfs-common nfs-utils rpcbind
mkdir /nfs
chown 777 /nfs/
chown nfsnobody /nfs/
cat /etc/exports
/nfs *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind
systemctl start nfs
其他节点安装客户端
yum -y install nfs-utils rpcbind
测试NFS是否可用
mkdir /test
showmount -e 192.168.66.100
mount -t nfs 192.168.66.100:/nfs /test
cd /test
echo "iifsdfsdf" > /test/1.html
cd ..
umount /nfs
rm -rf /nfs
II、部署 PV
mkdir ~/pv
cd ~/pv
vim py.yaml
kubectl create -f pv.yaml
kubectl get pv
III、创建服务并使用 PVC
mkdir /nfs{1..3}
[root@hub ~]# cat /etc/exports
mkdir /nfs{1..3}
chmod 777 /nfs{1..3}
chown nfsnobody /nfs{1..3}
systemctl restart rpcbind
systemctl restart nfs
在其他节点测试:
mount -t nfs 192.168.66.100:/nfs1 /test
echo "22" > /test/index.html
umount /test/
rm -rf /test/
vim pv.yaml
kubectl create -f pv.yaml
kubectl get pv
调整一下nfspv3的类
vim pv1.yaml
kubectl delete pv nfspv3
kubectl create -f pv1.yaml
kubectl get pv
[root@k8s-master01 pv]# vim pod.yaml
kubectl apply -f pod.yaml
kubectl get pod
状态不对
kubectl describe pod web-1
没有对应的请求被绑定,因为yaml文件里面定义的条件和实际存在的pv不匹配。
排查:
查看PV
kubectl get pv
查看yaml
再看pod
yaml匹配要求类是nfs,访问控制列表要求是RWO,同时满足这两个条件的只有nfspv1,并且RWO只能绑定一个,所以第二个pod一直等待了,副本数定义的3个,但是由于有序部署,第二个状态不是ready或者running,第三个pod还没出来。
yaml定义的大小只要>=storage即可,满足条件后优先选择小资源的(最低要求)进行绑定。
调整:
改PV3和4符合要求的。
kubectl delete pv nfspv3 nfspv4
vim pv2.yaml
kubectl create -f pv2.yaml
ubectl describe pod web-2
kubectl get pv
vim pv2.yaml
kubectl delete -f pv2.yaml
kubectl create -f pv2.yaml
kubectl get pvc
kubectl describe pv nfspv1
在nfs上创建一个Index.html
[root@hub ~]# cd /nfs
[root@hub nfs]# ls
1.html
[root@hub nfs]# rm 1.html
rm:是否删除普通文件 "1.html"?y
[root@hub nfs]# echo "aaa" > index.html
[root@hub nfs]# chmod 777 index.html
[root@k8s-master01 pv]# kubectl get pod -o wide
curl 10.244.2.124
同理
kubectl get pvc
kubectl get pv
kubectl get pod -o wide
kubectl describe pv nfspv3
kubectl describe pv nfspv4
[root@hub nfs]# echo "bbb" > /nfs2/index.html
[root@hub nfs]# echo "ccc" > /nfs3/index.html
curl 10.244.1.104
curl 10.244.2.125
kubectl delete pod web-0
kubectl get pod -o wide
删除后保留副本又启了一个新的容器IP变了,访问名称还一致,测试 数据依然存在
可以通过 Pod域名或者FQDN访问同一个名称
关于 StatefulSet
匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,web-2
StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless servername),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化
StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(servicename).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名
根据 volumeClaimTemplates,为每个 Pod 创建一个 pvc,pvc 的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Podname=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 来实现。
有序收缩。
statefulset名称:
kubectl get pod -o wide
kubectl get svc
容器内需要用到ping,测试效果:
kubectl exec test-pd -it -- /bin/sh
StatefulSet的Headless地址:
kubectl get pod -o wide -n kube-system
dig -t A nginx.default.svc.cluster.local. @10.244.0.7
解析成功
启停顺序:
kubectl delete statefulset --all
kubectl get pod -w
kubectl create -f pv/pod.yaml
测试访问
kubectl delete -f pv/pod.yaml
[root@k8s-master01 pv]# kubectl get statefullset
[root@k8s-master01 pv]# kubectl get svc
kubectl delete svc nginx
kubectl get pv
kubectl get pvc
pod删除pvc并不会跟随删除
kubectl delete pvc --all
kubectl get pvc
kubectl get pv
状态已经变成Released(已释放)——声明被删除,但是资源还未被集群重新声明,之前是Bound(已绑定)——卷已经被声明绑定
先去删除数据
kubectl get pv
还是Released
kubectl get pv nfspv1 -o yaml
nfspv并不会检查文件数据,但是pv依然有使用者信息
手动回收
kubectl edit pv nfspv1
删除选中行
kubectl get pv
状态已经变成Available(可用)——一块空闲资源还没有被任何声明绑定
8.1、Kubernetes 调度器 - 调度说明
8.2、Kubernetes 调度器 - 调度亲和性
8.3、Kubernetes 调度器 - 污点
8.4、Kubernetes 调度器 - 固定节点
简介
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 :
apiVersion: v1
kind: Pod
metadata:
name: annotation-second-scheduler
labels:
name: multischeduler-example
spec:
schedulername: my-scheduler
containers:
name: pod-with-second-annotation-container
image: gcr.io/google_containers/pause:2.0
通过配置可以让不同pod处于同一节点或者不同节点
pod.spec.nodeAffinity
preferredDuringSchedulingIgnoredDuringExecution:软策略
requiredDuringSchedulingIgnoredDuringExecution:硬策略
查看键名
kubectl get node --show-labels
requiredDuringSchedulingIgnoredDuringExecution
硬策略:
测试一下NotIn效果:
[root@k8s-master01 ~]# mkdir affi
[root@k8s-master01 ~]# cd affi
[root@k8s-master01 affi]# vim pod1.yaml
这里的匹配关系是NotIn,意思是只要不是node02就可以运行,排除了node02
kubectl create -f pod1.yaml
kubectl get pod -o wide
节点在01上
kubectl delete pod --all && kubectl create -f pod1.yaml && kubectl get pod -o wide
改成运算关系改成In
vim pod1.yaml
kubectl delete pod --all && kubectl create -f pod1.yaml && kubectl get pod -o wide
kubectl delete pod --all && kubectl create -f pod1.yaml && kubectl get pod -o wide
只运行在02节点
改成03节点
kubectl delete pod --all && kubectl create -f pod1.yaml && kubectl get pod -o wide
状态不对
kubectl describe pod affinity
由于没有03节点,并且是硬策略,所以坚持在03上运行,最终报节点不匹配。
preferredDuringSchedulingIgnoredDuringExecution
软策略:
查看键名
kubectl get node --show-labels
vim pod3.yaml
这里配置的软策略期望hostname in 节点名node03
kubectl delete pod --all
kubectl create -f pod3.yaml && kubectl get pod -o wide
没有03软策略也会在其他节点运行
改成01
权重值是遇到重复时的优先权 0~100
kubectl delete -f pod3.yaml && kubectl create -f pod3.yaml && kubectl get pod -o wide
发现01优先,但是也有在02上运行的
改成硬策略:
kubectl delete -f pod3.yaml && kubectl create -f pod3.yaml && kubectl get pod -o wide
全都在node01上运行了
kubectl delete -f pod3.yaml
合体:
node节点不多,演示效果不太好
vim pod5.yaml
排除02节点,选择其他节点运行,并优先选择01
由于只有2个节点排除掉02以后只剩下01了
kubectl delete -f pod5.yaml
键值运算关系
In:label 的值在某个列表中
NotIn:label 的值不在某个列表中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在
Pod 亲和性
pod.spec.affinity.podAffinity/podAntiAffinity
preferredDuringSchedulingIgnoredDuringExecution:软策略
requiredDuringSchedulingIgnoredDuringExecution:硬策略
创建一个pod
vim pod6.yaml
kubectl get pod -o wide --show-labels
演示pod亲和性:
vim pod7.yaml
kubectl create -f pod7.yaml
kubectl get pod -o wide --show-labels
在同一拓扑域
修改不亲和
kubectl delete -f pod7.yaml
vim pod7.yaml
podAffinity改成podAntiAffinity
kubectl create -f pod7.yaml
kubectl get pod -o wide
由于是podAntiAffinity和硬限制,结果不在同一节点运行
kubectl delete -f pod7.yaml
如果是硬限制匹配labels不存在的话:
kubectl get pod -o wide --show-labels
vim pod7.yaml
kubectl get pod -o wide --show-labels
等待
describe pod pod-3
提示2个节点都不匹配运行
测试效果,改一下标签名成匹配的node02
kubectl label pod node01 app=node02
提示已经存在并且当前--overwrite is false
kubectl label pod node01 app=node02 --overwrite=True
kubectl get pod -o wide --show-labels
匹配到了,running了,节点也一样
亲和性/反亲和性调度策略比较如下:
Taint 和 Toleration
节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点 能够 排斥 一类特定的 pod
Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个taint ,这表示对于那些不能容忍这些Taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上
污点(Taint)
I、 污点 ( Taint ) 的组成
使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去
每个污点的组成如下:
key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 tainteffect 支持如下三个选项:
NoSchedule :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上
PreferNoSchedule :表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上
NoExecute :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去
kubectl get node
查看mster的污点配置
kubectl describe node k8s-master01
pod不会在master上运行,因为已经配置了污点
II、污点的设置、查看和去除
kubectl get pod -o wide
设置污点
kubectl taint nodes k8s-node01 check=yyq:NoExecute (kubectl taint nodes node1 key1=value1:NoSchedule)
由于是单独的pod被删除以后就没有了,如果是deployment控制的Pod会在node02上再起来
如果把02也设置污点
kubectl taint nodes k8s-node02 check=yyq:NoExecute
kubectl create -f pod1.yaml
kubectl get pod
容忍污点
vim pod8.yaml
这里设置了之前污点命令的参数和值,并且tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Pod 上继续保留运行的时间
配置了容忍已经可以运行起来了
kubectl delete pod pod-3
有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint nodes Node-Name node-ole.kubernetes.io/master=:PreferNoSchedule
kubectl get node
kubectl taint nodes k8s-master01 node-role.kubernetes.io/master=:PreferNoSchedule
调整成尽可能不在master01上运行,也就是说如果node节点资源不够用或者不可用,会在master01上运行。
vim pod9.yaml
kubectl create -f pod9.yaml
kubectl get pod
和预想结果不一样还是没有运行,查看问题
kubectl describe pod pod-3
提示3个节点pod都无法容忍
查看master01节点污点设置
kubectl describe node k8s-master01
配置无法替换,叠加了
把NoSchedule污点去除
kubectl taint nodes k8s-master01 node-role.kubernetes.io/master=:NoSchedule-
再查看
kubectl describe node k8s-master01
kubectl get pod -o wide
由于matser之前没有下载过镜像,并且镜像仓库目前权限是私人,而且没有配置Secret
docker login hub.yyq.com
docker pull hub.yyq.com/library/mynginx:v1
kubectl get pod -o wide
清除污点
taint nodes k8s-node01 check=yyq:NoExecute-
taint nodes k8s-node02 check=yyq:NoExecute-
kubectl describe node k8s-node01
kubectl describe node k8s-node02
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容忍 ( Toleration ) ,意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上
pod.spec.tolerations
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
其中 key, vaule, effect 要与 Node 上设置的 taint 保持一致
operator 的值为 Exists 将会忽略 value 值
tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Pod 上继续保留运行的时间
I、当不指定 key 值时,表示容忍所有的污点 key:
tolerations:
II、当不指定 effect 值时,表示容忍所有的污点作用
tolerations:
III、有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule
指定节点名称或者label来进行强制选择。
指定调度节点
I、Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配
mkdir /root/nod
cd /root/node
vim pod1.yaml
配置根据节node01点选择
kubectl apply -f pod1.yaml
kubectl get pod -o wide
II、Pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到目标节点,该匹配规则属于强制约束
vim pod2.yaml
定义了只在disk:ssd的节点上运行
kubectl delete deployment --all
kubectl delete pod --all
kubectl apply -f pod2.yaml
kubectl get pod
由于不满足disk:ssd的条件,没有运行
通过修改标签完成测试
kubectl label node k8s-node01 disk=ssd
kubectl get pod
把node02也改成ssd
kubectl label node k8s-node02 disk=ssd
增加副本数
kubectl get deployment
kubectl edit deployment myweb11
kubectl get pod -o wide
9.1机制说明
9.2认证
9.3鉴权
9.4准入控制
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 里放入 Token
HTTP Base 认证:通过 用户名+密码 的方式认证
用户名+:+密码 用 BASE64 算法进行编码后的字符串放在 HTTP Request 中的 HeatherAuthorization 域里发送给服务端,服务端收到后进行编码,获取用户名及密码
最严格的 HTTPS 证书认证:基于 CA 根证书签名的客户端身份认证方式(双向)
I、HTTPS 证书认证:
II、需要认证的节点
两种类型
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 双向认证
证书颁发
手动签发:通过 k8s 集群的跟 ca 进行签发 HTTPS 证书
自动签发:kubelet 首次访问 API Server 时,使用 token 做认证,通过后,Controller Manager 会为kubelet 生成一个证书,以后的访问都是用证书做认证了
III、kubeconfig
kubeconfig 文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥),集群context 信息(集群名称、用户名)。Kubenetes 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群
[root@k8s-master01 node]# cat ~/.kube/config
包含了集群的访问方式和认证信息
IV、ServiceAccount
Pod中的容器访问API Server。因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。Kubenetes使用了Service Account解决Pod 访问API Server的认证问题
V、Secret 与 SA 的关系
Kubernetes 设计了一种资源对象叫做 Secret,分为两类,一种是用于 ServiceAccount 的 service-account-token, 另一种是用于保存用户自定义保密信息的 Opaque。ServiceAccount 中用到包含三个部分:Token、ca.crt、namespace
token是使用 API Server 私钥签名的 JWT。用于访问API Server时,Server端认证
ca.crt,根证书。用于Client端验证API Server发送的证书
namespace, 标识这个service-account-token的作用域名空间
kubectl get secret --all-namespaces
kubectl describe secret default-token-5gm9r --namespace=kube-syste
默认情况下,每个 namespace 都会有一个 ServiceAccount,如果 Pod 在创建时没有指定 ServiceAccount,就会使用 Pod 所属的 namespace 的 ServiceAccount
kubectl get pod -n kube-system
kubectl exec kube-proxy-m5fw7 -n kube-system -it -- /bin/sh
ls /run/secrets/kubernetes.io/serviceaccount
总结
!---->
Authorization
上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。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
I、RBAC 的 API 资源对象说明
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 authenticationfile 验证 =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:
ClusterRole 具有与 Role 相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的,ClusterRole 可以用于:
集群级别的资源控制( 例如 node 访问权限 )
非资源型 endpoints( 例如 /healthz 访问 )
所有命名空间资源控制(例如 pods )
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
name: secret-reader
rules:
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 来引用
例如,以下 RoleBinding 引用了一个 ClusterRole,这个 ClusterRole 具有整个集群内对 secrets 的访问权限;但是其授权用户 dave 只2能访问 development 空间中的 secrets(因为 RoleBinding 定义在 development 命名空间)
# This role binding allows "dave" to read secrets in the "development" namespace.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets
namespace: development # This only grants permissions within the "development" namespace.
subjects:
kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
使用 ClusterRoleBinding 可以对整个集群中的所有命名空间资源权限进行授权;以下 ClusterRoleBinding 样例展示了授权 manager 组内所有用户在全部命名空间中对 secrets 进行访问
# This cluster role binding allows anyone in the "manager" group to read secrets in any
namespace.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets-global
subjects:
Resources
Kubernetes 集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;同时某些资源也会包含子资源,例如 logs 资源就属于 pods 的子资源,API 中 URL 样例如下
GET /api/v1/namespaces/{namespace}/pods/{name}/log
如果要在 RBAC 授权模型中控制这些子资源的访问权限,可以通过 / 分隔符来实现,以下是一个定义 pods 资资源logs 访问权限的 Role 定义样例
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
to Subjects
RoleBinding 和 ClusterRoleBinding 可以将 Role 绑定到 Subjects;Subjects 可以是 groups、users 或者service accounts
Subjects 中 Users 使用字符串表示,它可以是一个普通的名字字符串,如 “alice”;也可以是 email 格式的邮箱地址,如 “wangyanglinux@163.com”;甚至是一组字符串形式的数字 ID 。但是 Users 的前缀 system: 是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式
Groups 书写格式与 Users 相同,都为一个字符串,并且没有特定的格式要求;同样 system: 前缀为系统保留
实践:创建一个用户只能管理 dev 空间
[root@k8s-master01 ~]# useradd devuser
[root@k8s-master01 ~]# passwd devuser
ssh devuser@192.168.66.10
[devuser@k8s-master01 ~]$ kubectl get pod
The connection to the server localhost:8080 was refused - did you specify the right host or port?
没有权限,创建证书请求:
cd /usr/local/install-k8s/cert/devuser
vim devuser-csr.json
cd /usr/local/bin/
生成证书
cd /etc/kubernetes/pki/
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /usr/local/install-k8s/cert/devuser/devuser-csr.json | cfssljson -bare devuser
ls
# 设置集群参数
cd /usr/local/install-k8s/cert/devuser/
export KUBE_APISERVER="https://192.168.66.10:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig
# 设置客户端认证参数
创建devuser证书、指定客户端证书、客户端私钥、开启认证方式、写入文件
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/pki/devuser.pem \
--client-key=/etc/kubernetes/pki/devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig
cat devuser.kubeconfig
多了用户名、用户证书、用户私钥信息
创建名称空间
kubectl create namespace dev
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig
cat devuser.kubeconfig 多了namespace和用户名信息
创建一个rolebinding,devuser可以在dev名称空间下有管理员权限
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev
[devuser@k8s-master01 ~]$ mkdir .kube
[root@k8s-master01 devuser]# cp devuser.kubeconfig /home/devuser/.kube/config
chown devuser:devuser /home/devuser/.kube/config
[devuser@k8s-master01 .kube]$ kubectl config use-context kubernetes --kubeconfig=config
kubectl get pod
kubectl run nginx --image=hub.yyq.com/library/mynginx:v1
kubectl get pod
kubectl get pod --all-namespaces -o wide | grep nginx
kubectl get pod -n default
只定义了dev没有定义default无法访问。
准入控制
准入控制是API Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的 1.14 的推荐列表是:
NamespaceLifecycle,
LimitRanger,
ServiceAccount,
DefaultStorageClass,
DefaultTolerationSeconds,
MutatingAdmissionWebhook,
ValidatingAdmissionWebhook,
ResourceQuota
列举几个插件的功能:
NamespaceLifecycle: 防止在不存在的 namespace 上创建对象,防止删除系统预置 namespace,删除namespace 时,连带删除它的所有资源对象。
LimitRanger:确保请求的资源不会超过资源所在 Namespace 的 LimitRange 的限制。
ServiceAccount: 实现了自动化添加 ServiceAccount。
ResourceQuota:确保请求的资源不会超过资源的 ResourceQuota 限制。
helm命令详解
http://www.coderdocument.com/docs/helm/v2/helm_commands/helm_repo_add.html#helm-repo-add
10.1 部署 Helm
包管理工具(类linux yum)下yaml文件
10.2 使用 Helm 部署 dashboard
10.3 使用 Helm 部署 metrics-server
10.4 部署 prometheus
10.5 部署 EFK 平台
https://github.com/helm/helm/blob/master/docs/charts.md
什么是 Helm
在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm 通过打包的方式,支持发布的版本管理和控制,很大程度上简化了 Kubernetes 应用的部署和管理
Helm 本质就是让 K8s 的应用管理(Deployment,Service 等 ) 可配置,能动态生成。通过动态生成 K8s 资源清单文件(deployment.yaml,service.yaml)。然后调用 Kubectl 自动执行 K8s 资源部署
Helm 是官方提供的类似于 YUM 的包管理器,是部署环境的流程封装。Helm 有两个重要的概念:chart 和release
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版本:
ntpdate ntp1.aliyun.com
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
tar -zxvf helm-v2.13.1-linux-amd64.tar.gz
cd linux-amd64/
cp helm /usr/local/bin/
为了安装服务端 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 文件:
[root@k8s-master01 helm]# vim rbac.yaml
kubectl create -f rbac.yaml
helm init --service-account tiller --skip-refresh
tiller 默认被部署在 k8s 集群中的 kube-system 这个namespace 下
kubectl get pod -n kube-system -l app=helm
kubectl describe pod tiller-deploy-58565b5464-f55cv -n kube-system
docker pull gcr.io/kubernetes-helm/tiller:v2.13.1
或者
docker load -i helm-tiller.tar
kubectl get pod -n kube-system -l app=helm
helm version
自己找helm如reids:
访问 hub.helm.sh
Helm 自定义模板
# 创建文件夹
[root@k8s-master01 helm]# mkdir test && cd test
# 创建自描述文件 Chart.yaml , 这个文件必须有 name 和 version 定义
$ cat <<'EOF' > ./Chart.yaml
name: hello-world
version: 1.0.0
EOF
# 创建模板文件, 用于生成 Kubernetes 资源清单(manifests)
$ mkdir ./templates
vim ./deployment.yaml
vim ./templates/service.yaml
# 使用命令 helm install RELATIVE_PATH_TO_CHART 创建一次Release
helm install .
# 列出已经部署的 Release
helm ls
helm upgrade tinseled-dolphinhelm upgrade tinseled-dolphin .
helm list
helm history tinseled-dolphin
也可以通过helm看
# 查询一个特定的 Release 的状态
helm status tinseled-dolphin
浏览器访问:192.168.66.10:31586
# 配置体现在配置文件 values.yaml
[root@k8s-master01 test]# vim values.yaml
# 这个文件中定义的值,在模板文件中可以通过 .VAlues对象访问到
$ vim ./templates/deployment.yaml
helm list
helm upgrade tinseled-dolphin .
kubectl get pod
刷新网页
已经更新版本
# 返回v1版本
helm upgrade tinseled-dolphin --set image.tag='v1' .
其他命令:
# 移除所有与这个 Release 相关的 Kubernetes 资源
#$ helm delete tinseled-dolphin
再重新创建
helm install --name tinseled-dolphin .
提示已存在
helm list --deleted
还有保存的信息,默认保存 用于恢复,回滚:
helm rollback tinseled-dolphin 8
浏览器访问:192.168.66.10:31344
版本变了,端口变了
[root@k8s-master01 test]# helm rollback tinseled-dolphin 4
# 如果想要全删除需要添加 --perge参数
helm delete --purge tinseled-dolphin
helm list --deleted
历史已空
Debug
# 使用模板动态生成K8s资源清单,非常需要能提前预览生成的结果。
# 使用--dry-run --debug 选项来打印出生成的清单文件内容,而不执行部署
helm install . --dry-run --debug --set image.tag=latest
helm install --dry-run .
helm list
使用Helm部署 dashboard
cd /usr/local/install-k8s/plugin/dashboard
下载远程安装包到本地。
helm fetch stable/kubernetes-dashboard
提示repo更新
helm repo update
遇到Unable to get an update from the “stable” chart repository (https://kubernetes-charts.storage.googleapis.com) 错误
手动更换stable 存储库为阿里云的存储库
helm repo remove stable
helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
helm repo update
查看已有仓库
helm repo list
helm fetch stable/kubernetes-dashboard
vim kubernetes-dashboard.yaml
helm install . \
-n kubernetes-dashboard \
--namespace kube-system \
-f kubernetes-dashboard.yaml
kubectl -n kube-system get secret | grep kubernetes-dashboard-token
scp dashboard.tar root@192.168.66.20:/root/
scp dashboard.tar root@192.168.66.21:/root/
kubectl delete pod kubernetes-dashboard-79599d7b8d-ms9tb -n kube-system
kubectl get svc -n kube-system
kubectl edit svc -n kube-system kubernetes-dashboard
修改 ClusterIP 为 NodePort
[root@k8s-master01 kubernetes-dashboard]# kubectl get svc -n kube-system
浏览器访问https://192.168.66.10:32756
浏览器非可信CA不可访问
可以把证书导入本机 sz /etc/kubernetes/pki/ca.crt 或者使用火狐浏览器访问
接受
查看 token令牌
kubectl -n kube-system get secret | grep kubernetes-dashboard-token
kubectl describe secret kubernetes-dashboard-token-h8tl4 -n kube-system
复制
点击创建部署新应用
点击部署
kubectl get pod -n kube-system
prometheus集成了 metrics-server可跳过直接部署9.4 prometheus
使用Helm部署metrics-server
从 Heapster 的 github <https://github.com/kubernetes/heapster >中可以看到已经,heapster 已经DEPRECATED。这里是 heapster的deprecation timeline。 可以看出 heapster 从 Kubernetes 1.12 开始将从 Kubernetes 各种安装脚本中移除。Kubernetes 推荐使用 metrics-server。我们这里也使用helm来部署metrics-server。
metrics-server.yaml:
args:
helm install stable/metrics-server \
-n metrics-server \
--namespace kube-system \
-f metrics-server.yaml
使用下面的命令可以获取到关于集群节点基本的指标信息:
kubectl top node
相关地址信息
Prometheus github 地址:https://github.com/coreos/kube-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:是可视化数据统计和监控平台。
构建记录
git clone https://github.com/coreos/kube-prometheus.git
cd kube-prometheus/manifests
修改 grafana-service.yaml 文件,使用 nodepode 方式访问 grafana:
vim grafana-service.yaml
修改:
type: NodePort
nodePort: 30100
修改 prometheus-service.yaml 文件,使用 nodepode 方式访问 grafana:
vim prometheus-service.yaml
修改:
type: NodePort
nodePort: 30200
修改 alertmanager-service.yaml 文件,使用 nodepode 方式访问 grafana:
vim alertmanager-service.yaml
修改:
type: NodePort
nodePort: 30300
导入镜像
/usr/local/install-k8s/plugin/prometheus
tar -zxvf prometheus.tar.gz
cat load-images.sh
#!/bin/bash
cd /root/prometheus
ls /root/prometheus | grep -v load-images.sh > /tmp/k8s-images.txt
for i in $( cat /tmp/k8s-images.txt )
do
docker load -i $i
done
rm -rf /tmp/k8s-images.txt
[root@k8s-master01 prometheus]# mv prometheus load-images.sh /root/
cd
chmod a+x load-images.sh
./load-images.sh
scp -r prometheus/ load-images.sh root@k8s-node01:/root
scp -r prometheus/ load-images.sh root@k8s-node02:/root
.[root@k8s-node01 ~]# ./load-images.sh
.[root@k8s-node02 ~]# ./load-images.sh
cd /usr/local/install-k8s/plugin/prometheus/kube-prometheus/manifests
kubectl apply -f ../manifests/
由于会互相连接多执行几次
如果遇到报错namespaces "monitoring" not found 就执行一遍 kubectl apply -f ../manifests/setup/ 再执行 kubectl apply -f ../manifests/
ntpdate ntp1.aliyun.com
kubectl get pod -n monitoring
kubectl get svc --all-namespaces
其中k8s.gcr.io/addon-resizer:1.8.4镜像被墙,无法下载,所以需要先通过阿里云下载下来,再传入本地镜像仓库
docker pull registry.cn-beijing.aliyuncs.com/minminmsn/addon-resizer:1.8.4
docker tag registry.cn-beijing.aliyuncs.com/minminmsn/addon-resizer:1.8.4 k8s.gcr.io/addon-resizer:1.8.4
kubectl get svc --all-namespaces
kubectl get pod -n monitoring -o wideipvsadm -Ln | grep -E "192.168.66.10:30300|192.168.66.10:30200|192.168.66.10:30100" -A 3
kubectl top node
top pod -n kube-system
浏览器访问prometheus收集端
192.168.66.10:30200
通过访问 http://MasterIP:30200/target 可以看到 prometheus 已经成功连接上了 k8s 的 apiserver
prometheus 的 WEB 界面上提供了基本的查询 K8S 集群中每个 POD 的 CPU 使用情况,查询条件如下:
sum by (pod_name)( rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m] ) )
kubectl get service -n monitoring | grep grafana
浏览器访问grafana
http://MasterIP:30100
如上可以看到 grafana 的端口号是 30100, 用户名密码默认 admin/admin
首次登陆修改密码
自带了很多模板
Horizontal Pod Autoscaling
Horizontal Pod Autoscaling 可以根据 CPU 利用率自动伸缩一个 Replication Controller、Deployment 或者Replica Set 中的 Pod 数量
创建一个apache,hpa限制请求资源cpu 200m
kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m --expose --port=80
网络问题无法pull
docker tag gcr.io/google_containers/hpa-example:latest gcr.io/google_containers/hpa-example:v1
kubectl run php-apache --image=gcr.io/google_containers/hpa-example:v1 --requests=cpu=200m --expose --port=80
[root@k8s-master01 prometheus]# kubectl top pod php-apache-5bb5df8bd4-lb86l
创建 HPA 控制器 - 相关算法的详情请参阅这篇文档
CPU超过50%自动创建,最多10个
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
kubectl get hpa
增加负载,查看负载节点数目
kubectl run -i --tty load-generator --image=busybox /bin/sh
while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
kubectl get hpa -w
kubectl get pod -o wide
已经扩展满了
关闭压力测试,等待cpu下来,然后pod会减少到1个
资源限制 - Pod
Kubernetes 对资源的限制实际上是通过 cgroup 来控制的,cgroup 是容器的一组用来控制内核如何运行进程的相关属性集合。针对内存、CPU 和各种设备都有对应的 cgroup
默认情况下,Pod 运行没有 CPU 和内存的限额。 这意味着系统中的任何 Pod 将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU 和内存 。一般会针对某些应用的 pod 资源进行资源限制,这个资源限制是通过resources 的 requests 和 limits 来实现
requests相当于软限制,limits相当于硬限制
spec:
containers:
requests 要分分配的资源,limits 为最高请求的资源值。可以简单理解为初始值和最大值
资源限制 - 名称空间
I、计算资源配额
apiVersion: v1
kind: ResourceQuota # 资源配额
metadata:
name: compute-resources #名称
namespace: spark-cluster #名称空间
spec:
hard:
pods: "20" #能够创建的Pod数量
requests.cpu: "20" #能够使用的requests cpu20个
requests.memory: 100Gi #内存
limits.cpu: "40"
limits.memory: 200Gi
II、配置对象数量配额限制
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: spark-cluster
spec:
hard:
configmaps: "10"
persistentvolumeclaims:"4" #PVC
replicationcontrollers:"20" #RC
secrets: "10"
services: "10"
services.loadbalancers:"2" #基于云服务器负载的方案
III、配置 CPU 和 内存 LimitRange
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
[root@k8s-master01 containers]# cd /usr/local/install-k8s/
[root@k8s-master01 install-k8s]# mkdir efk && cd efk
helm fetch incubator/elasticsearch
添加 Google incubator 仓库
helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
部署 Elasticsearch
kubectl create namespace efk
helm fetch incubator/elasticsearch
helm install --name els1 --namespace=efk -f values.yaml incubator/elasticsearch
kubectl run cirror-$RANDOM --rm -it --image=cirros -- /bin/sh
curl Elasticsearch:Port/_cat/nodes
部署 Fluentd (未使用Logstash因为Fluentd使用GO语言开发更轻量、消耗资源小,但还是Logstash功能更强)
helm fetch stable/fluentd-elasticsearch
vim values.yaml
# 更改其中 Elasticsearch 访问地址
helm install --name flu1 --namespace=efk -f values.yaml stable/fluentd-elasticsearch
部署 kibana
helm fetch stable/kibana --version 0.14.8
helm install --name kib1 --namespace=efk -f values.yaml stable/kibana --version 0.14.8
ls /var/log/containers/
F收集node节点log信息,传给E,再用K进行数据展示
查看SA\CA证书到日期
openssl x509 -in apiserver.crt -text -noout
openssl x509 -in ca.crt -text -noout
证书可用时限
1、go 环境部署
wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz
tar -zxvf go1.12.1.linux-amd64.tar.gz -C /usr/local
vi /etc/profile
export PATH=$PATH:/usr/local/go/bin
source /etc/profile
go version
2、下载源码
cd /data && git clone https://github.com/kubernetes/kubernetes.git
git checkout -b remotes/origin/release-1.15.1 v1.15.1
3、修改 Kubeadm 源码包更新证书策略
vim staging/src/k8s.io/client-go/util/cert/cert.go # kubeadm 1.14 版本之前
vim cmd/kubeadm/app/util/pkiutil/pki_helpers.go # kubeadm 1.14 至今
const duration365d = time.Hour * 24 * 365 * 10
NotAfter:time.Now().Add(duration365d).UTC(),
make WHAT=cmd/kubeadm GOFLAGS=-v
cp _output/bin/kubeadm /root/kubeadm-new
4、更新 kubeadm
# 将 kubeadm 进行替换
cp /usr/bin/kubeadm /usr/bin/kubeadm.old
cp /root/kubeadm-new /usr/bin/kubeadm
chmod a+x /usr/bin/kubeadm
5、更新各节点证书至 Master 节点
cp -r /etc/kubernetes/pki /etc/kubernetes/pki.old
cd /etc/kubernetes/pki
kubeadm alpha certs renew all --config=/usr/local/install-k8s/core/kubeadm-config.yaml
openssl x509 -in apiserver.crt -text -noout | grep Not
6、HA集群其余 mater 节点证书更新
#!/bin/bash
masterNode="192.168.66.20 192.168.66.21"
#for host in ${masterNode}; do
# scp /etc/kubernetes/pki/{ca.crt,ca.key,sa.key,sa.pub,front-proxy-ca.crt,front-proxy-ca.key}
"${USER}"@$host:/etc/kubernetes/pki/
# scp /etc/kubernetes/pki/etcd/{ca.crt,ca.key} "root"@$host:/etc/kubernetes/pki/etcd
# scp /etc/kubernetes/admin.conf "root"@$host:/etc/kubernetes/
#done
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/{ca.crt,ca.key,sa.key,sa.pub,front-proxy-ca.crt,front-proxy-ca.key}
"${USER}"@$host:/root/pki/
scp /etc/kubernetes/pki/etcd/{ca.crt,ca.key} "root"@$host:/root/etcd
scp /etc/kubernetes/admin.conf "root"@$host:/root/kubernetes/
done
设置系统主机名以及 Host 文件的相互解析
hostnamectl
set-hostname
k8s-master01
安装依赖包
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget
vim
net-tools git
设置防火墙为 Iptables 并设置空规则
systemctl
stop firewalld
&&
systemctl
disable firewalld
yum -y install iptables-services
&&
systemctl
start iptables
&&
systemctl
enable iptables
&&
iptables -F
&&
service iptables save
关闭 SELINUX
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
调整内核参数,对于 K8S
cat > kubernetes.conf <
cp /boot/grub2/grub.cfg{,.bak}
grub2-mkconfig -o /boot/grub2/grub.cfg
--------------------------------------
kube-proxy开启ipvs的前置条件
modprobe br_netfilter
cat > /etc/sysconfig/modules/ipvs.modules <
安装 Kubeadm (主从配置)
cat <
\[kubernetes\]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86\_64
enabled=1
gpgcheck=0
repo\_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum -y
install
kubeadm-1.15.1 kubectl-1.15.1 kubelet-1.15.1
systemctl enable kubelet.service
初始化主节点
kubeadm config print init-defaults > kubeadm-config.yaml
kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs | tee kubeadm-init.log
加入主节点以及其余工作节点
执行安装日志中的加入命令即可
Etcd 集群状态查看
kubectl -n kube-system exec etcd-k8s-master01 -- etcdctl \
--endpoints=https://192.168.92.10:2379 \
--ca-file=/etc/kubernetes/pki/etcd/ca.crt \
--cert-file=/etc/kubernetes/pki/etcd/server.crt \
--key-file=/etc/kubernetes/pki/etcd/server.key cluster-health
kubectl get endpoints kube-controller-manager --namespace=kube-system
-o yaml
kubectl get endpoints kube-scheduler --namespace=kube-system
-o yaml
部署网络
kubectl apply -f kube-flannel.yml
手机扫一扫
移动阅读更方便
你可能感兴趣的文章