K8s笔记
K8sbrog重构, GO语言编写1. 特性自动部署应用容器自我修复当容器失败时,会对容器进行重新部署;服务完全启动成功后,才对外提供服务弹性伸缩使用命令、 UI或者基于CPU使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源, 以最小成本运行服务自动部署和回滚滚动更新应用,一次更新一个pod,如果更新过程中出现问题,将回滚更改,确保升级不受影响业务服务发
K8s
brog重构, GO语言编写
1. 特性
-
自动部署应用容器
-
自我修复
当容器失败时,会对容器进行重新部署;服务完全启动成功后,才对外提供服务
-
弹性伸缩
使用命令、 UI或者基于CPU使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源, 以最小成本运行服务
-
自动部署和回滚
滚动更新应用,一次更新一个pod,如果更新过程中出现问题,将回滚更改,确保升级不受影响业务
-
服务发现和负载均衡
K8s为多个容器提供一个统一访问入口(内部IP和一个DNS名称),并且负载均衡关联的所有容器,用户无需考虑容器IP问题
-
密钥和配置管理
管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在K8S中,方便应用程序使用
-
存储编排
挂载外部存储系统,无论是来自本地存储,公有云(如阿里云、AWS),还是网络存储(如NFS、 GlusterFS、 Ceph)都作为集群资源的一部分使用,极大提高存储使用灵活性。
-
批处理
提供一次性任务,定时任务;满足批量数据处理和分析的场景
2. 架构组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4HAJhWJn-1617715990606)(C:\Users\XiaoJin\AppData\Roaming\Typora\typora-user-images\image-20210217153410730.png)]
Master(主控节点)
-
API Server
(1)集群统一入口,各组件协调者, 以RESTful API提供接口服务,用户通过 api server 来管理整个容器集群平台。所有对象资源的增删改查和监听操作都交给API Server处理后再提交给Etcd存储。
(2)API Server 负责和 etcd 交互(其他组件不会直接操作 etcd,只有 API Server 这么做),整个 kubernetes 集群的所有的交互都是以 API Server 为核心的。
如:1、所有对集群进行的查询和管理都要通过 API 来进行
2、所有模块之间并不会互相调用,而是通过和 API Server 打交道来完成自己那部分的工作,API Server提供的验证和授权保证了整个集群的安全
-
scheduler
节点调度,根据调度算法为新创建的Pod选择一个Node节点;负责接收任务,选择合适的节点进行分配
-
controller-manager
所有资源对象的自动化控制中心,处理集群中常规后台任务,一个资源对应一个控制器,而Controller Manager就是负责管理这些控制器的;维持副本期望数
-
etcd
键值对数据库,存储k8s集群所有重要信息(持久化)
Node(工作节点)
-
kubelet
相当于Master派到Node节点上的一个代表,负责管控容器;直接根容器交互
-
kube-proxy
操作iptables、IPVS在Node节点上实现Pod的网络映射和负载均衡
-
docker
容器引擎,运行容器。每一个Node都会运行一个docker引擎,其负责下载镜像和运行容器。Kubernetes本身并不提供容器软件运行环境,但提供了接口,可以安装所选择的容器软件环境。
-
coredns
可以为集群中的服务创建一个域名IP的对应关系解析
-
dashboard
给k8s提供一个b/s结构的访问体系
3. 核心概念
-
Pod
是Kurbernetes进行创建、调度和管理的最小单位,一个pod包含一个或者多个紧密相连的业务容器(即一组容器的集合)
Kubernetes为每个Pod都分配了唯一的IP地址,称之为PodIP,一个Pod里的多个容器共享PodIP地址,它负责外部跟容器之间进行通信
-
controller
确保预期的Pod副本数量
有状态应用部署;无状态应用部署
确保所有的node运行同一个pod
一次性任务和定时任务
-
Service
定义一组pod的访问规则
通过虚拟一个访问 IP 及服务端口,可以访问我们定义好的 Pod 资源,是通过 iptables 的 nat 转发来实现,转发的目标端口为Kube_proxy 生成的随机端口
4. Pod
一个pod里面可能有多个容器,运行pause,容器公用pause的网络站,公用pause的存储卷,进程不会进行隔离;不能端口冲突
- 自主式pod(一旦死了,不会进行拉起)
- 控制器管理的Pod(死亡后,控制器进行拉起)
4.1 Pod控制器类型
(1)ReplicaSet
代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态
标签选择器,判断哪个Pod归自己管
当现存的pod数量不足,会根据pod资源模板进行新建帮助用户管理无状态的pod资源,精确反应用户定义的目标数量,但是RelicaSet不是直接使用的控制器,而是使用Deployment。
(2)Deployment
工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。并且其支持滚动更新,回滚,deployment创建出RS,RS来创建pod。更新的时候RS并没有删除,而是停用,然后创建新的RS,RS再去创建对应的pod,当回滚的时候,deployment会停用现在的RS,启用之前的RS,然后再滚动创建pod回滚
(3)HPA
仅适用于deployment和RS 在v1版中仅支持根据pod的CPU利用率扩容,在vlapha版本中 支持根据内存和用户自定义的metric扩容缩容
(3)statefulset:是为了解决有状态服务的问题
稳定存储: 当pod重新调度以后,还会继续使用之前的数据,并且数据相同没有丢
稳定网络位: 当pod重新调度以后,pod的名字不会更改
有序部署: 当前一个pod处于running的状态,才会创建第二个pod,用于依赖,针对启动有顺序的服务比如先启动mysql,再启动nginx
有序删除: 删除也是按照顺序去删除
(4)daemonset
确保全部node节点上运行一个pod的副本。当有node加入集群时,也会为他们新增一个pod。当有node从集群移除时,这些pod也会被回收,删除daemonset将会1删除1他们创建的所有的pod
(5)job,cronjob
负责批处理任务
4.2 网络通讯模式
基本原则:每个pod都有一个独立的IP;
设计原因:用户不需要额外考虑如何建立pod之间的连接,也不需要将容器端口映射到主机端口的问题
网络要求:所有的容器都可以在不同NAT的情况下和其他容器进行通信;
- 同一个Pod中容器间的通信
同一个Pod的容器共享同一个网络命名空间,它们之间使用Pause的一个网络协议栈,可以理解为它们之间的访问可以通过localhost地址和容器端口实现;
- 同一个node不同pod间的通信
同一Node不同Pod间是通过Docker网桥来进行数据包分配传输的,它们关联在同一个Docker0网桥上,地址网段相同,IP1、IP2、IP3属于同一个网段,所以它们之间能通信
- 不同node间的pod通信(基于flannel)
- Flannel
让集群的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。而且它还能够在这些IP地址之间建立一个覆盖网络(overlayNetwork),通过这个覆盖网络将数据包原封不动的传递到对应的目标容器内。
Flannel相当于一个守护进程,它会监听一个端口,这个端口就是后续进行数据转发和数据接受的一个服务端口,如果Flannel成功启动,它就会开启一个Flannel0 的一个网桥,这个网桥专门去收集Docker0转发出来的数据包,可以理解为一个钩子函数;
Flanneld这里会有一堆的路由表信息,它是存储在etcd中由Flannel去自动拉取的,不同Pod间的通信就需要这些路由表来确定具体的转发路径;
etcd对Flannel提供如下说明:
1、存储管理Flannel可分配的IP地址段资源;
2、监控ETCD中每个Pod的实际地址,并在内存中维护Pod节点路由表
通讯过程:
- app1将自身IP地址、目标IP及其所发数据发送至Docker0的网桥;
- Docker0获取到发送的数据包,由于目标IP的网段与当前Docker0的网段不是同一个,所以它会通过钩子函数抓取数据信息继续发送至Flannel0的网桥
- Flannel0网桥这时候会通过Flanneld中的路由表信息来确定具体的转发路径,此时会进行一个数据的二次封装,然后通过对应的外部节点IP(192.168.66.11/24)发送到目标外部IP(192.168.66.12/24)
- 发送到Node2节点之后会对数据包进行解析获取具体目标Pod的IP(10.1.20.3/24),然后发送到Backend从而完成整个Pod通信
- pod与service之间的通信
使用各节点的IPtables规则来进行网络通信
- Pod到外网:Pod向外网发送请求,查找路由表,转发数据包到宿主机的网卡,宿主网卡完成路由选择后,IPtables执行Masquerade,把源IP修改为宿主网卡的IP,然后向外网服务器发送请求;
- 外网访问Pod:通过service来访问,一般使用NodePort;
4.3 pod生命周期
- 1.kuctl向kubeApi发送指令
- 2.kubeApi会调用到kubelet(调度过程是通过etcd来完成的)
- 3.kubelet会对应操作cr
- 4.cr去完成容器环境的初始化,初始化过程中它会启动一个pause的基础容器,这是google给我们做的一个非常经典容器,他负责我们的网络和存储卷的共享,就是说同一个pod中,里面所有的容器都是共享的
- 5.接着cr会进行一个或者多个init C(容器)的初始化(这取决于你的pod中有多少个容器),当然init C也可以没有,Init C在初始化完成后要是正常退出,退出码会是0,如果是非0则是不正常退出。(前一个Init C如果没有正常退出,后一个是不会继续执行的)如果Pod的Init容器失败,kubernetes会不断重启该Pod(重启pod所有的Init都会重新执行),直到Init容器成功为止.然而如果Pod对应的restartPolicy为Never,他则不会重新启动
- 多个初始化的容器步骤完成后,就会进入MainC的运行了
- 在mainC刚start(启动)的时候,会允许他去执行一条命令或者一个命令脚本
- mainC在stop(关闭)的时候,也会允许他去执行一条命令,也就是我在退出的时候,我接下来要怎么办,交代后事
- 在start(启动)和stop(关闭)的过程中,会有readines和Liveness的参与
- readlines在容器运行多少秒后进行探测,在readines没有进行就绪检测之前,pod的状态不可能为running或者Read,当readlines检测之后,这个pod的状态才会变成running或者Read,在这个过程当中还有Liveness的参与。
- liveness他会伴随整个的主容器的生命周期,当主容器进程跟liveness检测结果不一致的时候,比如主容器出现损坏了或者不能正常工作了,那我就可以执行对应的重启,或者删除命令,这跟我们设定的策略有关
4.4 init C容器
pod能具有多个容器,应用运行在容器里面,但是他也可能有一个或多个先于应用容器启动的init 容器
- 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
- 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具。
- 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
- Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
- 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
- init容器总是运行到成功完成为止
- 每个init容器必须成功完成才会 运行下一个init容器
- 如果pod对应的init容器重启失败,k8s会不断的重启该pod,直到init容器成功启动;然而,pod对应的restartPolicy为never,它不会重新启动
在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。 每个容器必须在下一个容器启动之前成功退出。
如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试。 然而,如果 Pod 的 restartPolicy 设置为 Always,Init 容器失败时会使用 RestartPolicy策略。
在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。 Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 Pending 状态,但应该会将条件 Initializing 设置为 true
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
4.5 容器探针
探针 是由kubelet对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类型的处理程序:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
- livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。
- readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
- 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
- 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
- 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
- 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
- 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
readinessProbe
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
spec:
containers:
- name: httpget
image: nginx
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
livenessProbe-exec
apiVersion: v1
kind: Pod
metadata:
name: liveness
namespace: default
spec:
containers:
- name: liveness-exec
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/live ; sleep 60 ; rm -rf /tmp/live; sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
livenessProbe-httpGet
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: default
spec:
containers:
- name: nginx01
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10
livenessProbe-tcpSocket
apiVersion: v1
kind: Pod
metadata:
name: tcpsocket
namespace: default
spec:
containers:
- name: nginxv2
image: nginx
imagePullPolicy: IfNotPresent
livenessProbe:
initialDelaySeconds: 5
timeoutSeconds: 1
tcpSocket:
port: 80
start stop操作
apiVersion: v1
kind: Pod
metadata:
name: start
namespace: default
spec:
containers:
- name: nginxv3
image: nginx
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo hello > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
5. 资源清单
5.1 资源类型
- 名称空间级别:
- 工作负载型:Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob
- 服务发现及负载均衡:Service、ingress
- 配置与存储型:Volume(存储卷)、CSI(容器存储接口)
- 特殊类型的存储卷:ConfigMap(保存配置文件)、Secret(保存敏感数据)、DownwardAPI()
- 集群级别:
Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
- 元数据型:
HPA、PodTemplate、LimitRange
5.2 yaml格式
a.基本语法
- 缩进时只允许使用空格
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- #注释
b.支持的数据结构
- 对象:键值对的集合
#语法1:
name: steve
age: 18
#语法2:
hash: { name: steve,age: 18 }
- 数组:一组按次序排列的值,又称为序列
#语法1:
animal
- cat
- dog
#语法2:
animal: [cat,dog]
- 纯量:单个的、不可再分的值
字符串 布尔值 整数 浮点数 null 时间 日期
#数值直接以字面量的形式表示
number: 12.30
#布尔值用true和false表示
isSet: true
#null用~表示
parent: ~
#时间用ISO8601格式
iso8601: 2001-12-14t21:59:43.10-05:00
#日期
date: 2000-12-03
- 字符串
#默认不使用引号表示
str: 这是一行字符串
#如果字符串之中包含空格或特殊字符,需要放在引号之中
str: '内容: 字符串'
#单引号和双引号都可以使用,双引号不会对特殊字符进行转义
s1: '内容\n字符串'
s2: '内容\n字符串'
#单引号中如果还有单引号,必须使用两个单引号转义;''='
str: 'labor''s day'
#字符串可以写成多行,从第二行开始,必须有一个但空格缩进;换行符会被转为空格
str: 这是一段
多行
字符串
#换行符| >
this: |
aaa
bbb
that: >
aaa
bbb
5.3 常用字段
- 必须存在的属性
#参数名 字段类型 说明
version string 这里指的是k8s API的版本,目前基本上是v1,用kubectl api-versions查看
kind String yaml文件定义的资源类型和角色,比如:pod
metadata object 元数据对象,固定值就写metadata
metadata.name object 元数据对象的名字,由我们编写比如命名pod的名字
metadata.namespace string 元数据对象的命名空间,由我们定义
spec object 详细定义对象,固定值就写spec
spec.containers[] list 这里是spec对象的容器列表定义,是个列表
spec.containers[].name string 这里是定义容器名字
spec.containers[].image string 这里是定义镜像名称
- 主要对象
#参数名 字段类型 说明
spec.containers[].imagesPullPolicy string 定义镜像拉去策略
(1)Always:每次都重新拉去镜像
(2)Never:仅使用本地镜像
(3)ifNotPresent:有本地就使用本地,没有就拉取在线;默认always
spec.containers[].command[] list 指定容器启动命令,可以指定多个,不指定则使用镜像打包时使用的命令
spec.containers[].args[] list 指定容器启动命令参数,可以指定多个
spec.containers[].workingDir string 指定容器工作目录
spec.containers[].volumeMounts[] list 指定容器内部存储卷配置
spec.containers[].volumeMounts[].name string 指定可以被容器挂载的存储卷名称
spec.containers[].volumeMounts[].mountpath 指定可以被容器挂载的存储卷路径
spec.containers[].volumeMounts[].readOnly 设置存储卷读写模式,true或者false,默认读写
spec.containers[].ports[] list 指定容器用到的端口列表
spec.containers[].ports[].name string 指定端口名称
spec.containers[].ports[].containerPort string 指定容器需要监听的端口号
spec.containers[].ports[].hostPort string 指定容器所在主机需要监听的端口号
spec.containers[].ports[].protocol string tcp、udp
spec.containers[].env[] list 容器运行前的环境变量列表
spec.containers[].env[].name string 指定环境变量名称
spec.containers[].env[].value string 指定环境变量的值
spec.containers[].resources object 指定资源限制和资源请求的值
spec.containers[].resources.limits object 指定设置容器运行时的资源限制
spec.containers[].resources.limits.cpu string 指定cpu的限制,单位为core数
spec.containers[].resources.limits.memory 指定内存限制,MIB GIB
spec.containers[].resources.requests object 指定容器启动和调度时的限制设置
spec.containers[].resources.requests.cpu cpu请求,单位为core数,容器启动的初始化可用数量
spec.containers[].resources.requests.memory 指定内存限制,MIB GIB,容器启动的初始化可用数量
- 额外参数
#参数名 字段类型 说明
spec.restartPolicy string 定义pod重启策略
(1)Always:pod一旦死亡就会重启
(2)OnFailure:只有异常退出会重启
(3)Never:pod一旦死亡,不会重启
spec.nodeSelector object 定义node的label过滤标签,key:value格式
spec.imagePullSecrets object 定义pull镜像时使用secret名称,以name:secretkey格式
spec.hostNetwork Boolean 定义是否使用宿主机网络,默认false
5.4 常用命令
#创建容器
$ kubectl create -f *.yaml
#查看pod列表
$ kubectl get pod -o wide
#查看日志
$ kubectl log pod名称 -c 容器名称
#查看pod详细信息
$ kubectl describe pod pod名称
#查看svc
$ kubectl get svc
#查看pod的模板可配置的信息,api版本
$ kubectl expalin Pod
6. 资源控制器
用来控制Pod的具体状态和行为
- ReplicationController和ReplicaSet
ReplicationController(简称RC)是确保用户定义的Pod副本数保持不变,如果pod增多,会终止额外的Pod,如果减少,则会增加Pod
RS和RC没有本质上的不同,RS支持集合式的selector;RS支持标签匹配,以标签来监控副本数量
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx
image: nginx
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
- Deployment
Deployment为Pod和Replica Set提供声明式更新。
你只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换
- 定义deployment来创建RS管理Pod
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 4
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
#扩容
$ kubectl scale deployment nginx-deployment --replicas=10
#更新镜像
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
#回滚
$ kubectl rollout undo deployment/nginx-deployment
$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
#查看回滚状态
$ kubectl rollout status deployment/nginx-deployment
#查看回滚历史
$ kubectl rollout history deployment/nginx-deployment
$ kubectl rollout history deployment/nginx-deployment --revision=4
- DaemonSet
确保全部node节点上运行一个pod的副本。当有node加入集群时,也会为他们新增一个pod。当有node从集群移除时,这些pod也会被回收,删除daemonset将会1删除1他们创建的所有的pod
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
labels:
app: daemonset
spec:
selector:
matchLabels:
name: daemonset-example
template:
metadata:
labels:
name: daemonset-example
spec:
containers:
- name: nginx
image: nginx
- Job
负责批处理任务,仅执行一次的任务,保证批处理任务的一个或多个Pod成功结束
- template格式同Pod
- RestartPolicy仅支持Never或OnFailure
- 单个Pod时,默认Pod成功运行后Job即结束
- .spec.completions标志Job结束需要成功运行的Pod个数。默认为1
- .spec.parallelism标志并行运行的Pod个数,默认为1
- spec.activeDeadlineSeconds标志Pod的重试最大时间,超过这个时间不会继续重试
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
restartPolicy: Never
- CronJob
在特定时间循环创建Job
Cron Job管理基于时间的Job,即 : * * * * *
-
在给定的时间调度Job运行
-
创建周期性运行的Job,例如:数据库备份、发送邮件
-
.spec.schedule:调度,必须字段,指定任务运行周期
-
.spec.jobTemplate:job模板,必须字段,指定需要运行的任务,格式同Job
-
.spec.startingDeadlineSeconds:启动job的期限(秒级别),Job运行时间超过后,会被认为是失败的
-
.spec.concurrencyPolicy:并发策略
Allow:允许并发运行Job
Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
Replace:取消当前正在运行的Job,用一个新的来替换
-
.spec.supend:挂起后续的Job true false
-
.spec.successfulJobsHistoryLimit和.spec.failedJobsHistoryLimit:历史限制,指定了可以保留多少完成和失败的Job。默认情况下,他们分别设置为3和1.设置限制的值为0,相关类型的Job完成后将不会呗保留
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- c
- date; echo hello from k8s
restartPolicy: OnFailure
- StatefulSet
稳定的持久化存储,pod重新调度后还能访问到相同的持久化数据,基于PVC实现
稳定的网络标志,pod重新调度后其podname和hostname不变,基于headless service实现(没有cluster ip和service)
有序部署,有序扩展,pod是有顺序的,在部署或者扩展时要依据定义的顺序依次进行,基于init container来实现
有序收缩,有序删除
- Horizontal Pod Autoscaling
仅适用于deployment和RS 在v1版中仅支持根据pod的CPU利用率扩容,在vlapha版本中 支持根据内存和用户自定义的metric扩容缩容
7. Service 服务发现
出现场景,比如nginx配置了3台反向代理的pod副本,其中一个pod死了,资源控制器会重新创建一个pod,这个pod的ip地址会有变化,那么nginx配置文件中还是死掉的pod的IP地址
通过标签,为后端pod组成一个 逻辑分组,具有负载均衡功能, 并为它们提供一个统一的入口
Service只提供4层负载均衡能力,而没有7层功能
当客户端想访问svc的时候,其实就是访问iptables的规则
iptables的规则是通过kube-proxy写入的
apiserver通过监控bube-proxy来进行服务和端点信息的发现
kube-proxy通过pod的标签来判断是否把端点信息写入到对应svc
- service的4种类型
-
ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
apiserver,用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储在etcd
kubeproxy,这个进程负责感知service和pod的变化,将变化信息写入到本地的iptables规则中
#创建deployment apiVersion: apps/v1 kind: Deployment metadata: name: nginx-de namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: stabel template: metadata: labels: app: myapp release: stabel env: test spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 80 #创建svc apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: type: ClusterIP selector: app: myapp release: stabel ports: - name: http port: 80 targetPort: 80
-
NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由kube-proxy进一步给到对应pod
apiVersion: v1
kind: Service
metadata:
name: nodeport
namespace: default
spec:
type: NodePort
selector:
app: myapp
release: stabel
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30001
-
LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
-
ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。
- Headless Service
有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。
对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了 selector
apiVersion: v1
kind: Service
metadata:
name: headless
namespace: default
spec:
selector:
app: myapp
clusterIP: "None"
ports:
- port: 80
targetPort: 80
dig -t A headless.default.svc.cluster.local. @10.244.1.3
- service代理模式分类
7.1 Service Ingress
实现七层代理,统一端口
ingress是nginx实现的,通过nginx负载svc,svc再负载pod,以此实现七层代理
创建ingress资源就是定义好后端代理规则,然后将规则注入到nginx-controller里,然后nginx-controller会在nginx配置文件添加一个server块来代理svc。
而这个ingress规则写明了哪个域名对应k8s集群中的哪个service,然后再根据ingress-controller中的nginx配置模板,生成一段对应的nginx配置。
然后再把该配置动态的写到ingress-controller的pod里,该ingress-controller的pod里面运行着一个nginx服务,控制器会把生成的nginx配置写入到nginx的配置文件中,然后reload一下,使其配置生效。以此来达到域名分配置及动态更新的效果
部署ingress
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.25.0/deploy/static/mandatory.yaml
vim mandatory.yaml
...
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
# 添加
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- list
- watch
# 结束
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
#定义service
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30001
protocol: TCP
- name: https
port: 443
nodePort: 30002
targetPort: 443
protocol: TCP
selector:
app: ingress-nginx
通过域名访问实验
#定义service
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
---
#定义nginx-deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- name: http
containerPort: 80
---
#定义ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
spec:
rules:
- host: www.at.com
http:
paths:
- path: /
backend:
serviceName: nginx-svc
servicePort: 80
8.存储
8.1 ConfigMap
配置文件注册中心:不同的配置文件分配到后端不同的nginx上
创建pod时,可以指定ConfigMap,引用ConfigMap的键值,ConfigMap的键就是文件名,值就是文件内容
1、使用目录创建
$ mkdir configmap
$ vim game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRottencolor.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
$ 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/
2、使用文件创建
$ kubectl create configmap game-config-2 --from-file=/root/configmap/game.properties
3、使用字面值创建
$ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
4、使用资源清单创建
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
5、Pod中使用ConfigMap
#注入环境变量
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
command: [ "/bin/sh","-c","env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
envFrom:
- configMapRef:
name: env-config
restartPolicy: Never
6、用ConfigMap设置命令行参数
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
command: [ "/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
restartPolicy: Never
7、通过数据卷插件使用ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
command: [ "/bin/sh","-c","cat /etc/config/special.how" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
restartPolicy: Never
8、ConfigMap的热更新
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: log-config
$ kubectl exec my-nginx-6844885d5f-2gzfz -it -- cat /etc/config/log_level
INFO
#修改ConfigMap
$ kubectl edit configmap log-config
8.2 Secret
存储和管理一些敏感数据,比如密码,token,密钥等敏感信息。它把 Pod 想要访问的加密数据存放到 Etcd 中。然后用户就可以通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了
Secret有三种类型:
- Service Account
用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中
$ kubectl exec -n kube-system kube-proxy-9l6x5 -it -- ls /run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
- Opaque:
base64 编码格式的 Secret,用来存储密码、密钥等;但数据也可以通过base64 –decode解码得到原始数据,所有加密性很弱。
Opaque类型数据是一个map类型,要求value是base64编码格式
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "123.com" | base64
MTIzLmNvbQ==
#创建secret
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MTIzLmNvbQ==
username: YWRtaW4=
#创建pod
apiVersion: v1
kind: Pod
metadata:
labels:
name: secret-test
name: secret-test
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
- image: nginx
name: nginx
volumeMounts:
- name: secrets
mountPath: "/etc/secrets"
readOnly: true
$ kubectl exec secret-test -it -- ls /etc/secrets
password username
$ kubectl exec secret-test -it -- cat /etc/secrets/password
123.com
#将secret导出到环境变量中
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: pod
spec:
replicas: 2
template:
metadata:
labels:
app: pod
spec:
containers:
- name: pod-1
image: nginx
ports:
- containerPort: 80
env:
- name: TEST_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
$ kubectl exec pod-7f54f85c46-4fwns -it -- /bin/sh
# echo $TEST_USER
admin
# echo $TEST_PASSWORD
123.com
- kubernetes.io/dockerconfigjson
用来存储私有docker registry的认证信息
8.3 Volume
为了持久化保存容器的数据
本质上,Kubernetes Volume 是一个目录,这一点与 Docker Volume 类似。当 Volume 被 mount 到 Pod,Pod 中的所有容器都可以访问这个 Volume
Volume与Pod中的Pause绑定,pod中的容器共享Pause的存储卷
- emptyDir
一个 emptyDir Volume 是 Host 上的一个空目录。emptyDir Volume 对于容器来说是持久的,对于 Pod 则不是。当 Pod 从节点删除时,Volume 的内容也会被删除。但如果只是容器被销毁而 Pod 还在,则 Volume 不受影响。
用法:
临时空间,比如Web服务器写日志或者tmp文件需要的临时目录
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /cache
name: cache
volumes:
- name: cache
emptyDir: {}
- hostPath
pod挂载宿主机上的目录或文件,使得容器可以使用宿主机的文件系统进行存储。缺点是,在k8s中,pod都是动态在各node节点上调度。当一个pod在当前node节点上启动并通过hostPath存储了文件到本地以后,下次调度到另一个节点上启动时,就无法使用在之前节点上存储的文件
值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,在挂载 hostPath 卷之前不会执行任何检查 | |
DirectoryOrCreate | 将根据需要在那里创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组和权限 |
Directory | 给定的路径下必须存在目录 |
FileOrCreate | 会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组和权限 |
File | 给定的路径下必须存在文件 |
Socket | 给定的路径下必须存在 UNIX 套接字 |
CharDevice | 给定的路径下必须存在字符设备 |
BlockDevice | 给定的路径下必须存在块设备 |
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /test
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /root/data
type: Directory
8.4 PV-PVC
- PV
外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。定义了存储的类型,地址,大小,请求方式,回收策略。使用pv就相当于使用了存储
pv是集群资源,创建时无需指定命名空间
- PVC
用户存储请求,它与Pod相似,Pod消耗节点资源,PVC消耗PV资源,PVC通过声明请求存储的大小,访问方式以及标签,类等请求到pv,与pv进行绑定
- 使用流程
1.创建PV,与外部存储进行绑定
2.创建statefulset,statefulset中创建PVC模板,pod上面会有一个pvc
3.PVC会声明一些信息来与PV进行绑定
pvc请求大小如果有两个符合的pv,优先选择存储更小的pv
- PV访问模式
ReadWriteOnce
该卷可以被单个节点以读/写模式挂载
rwo
ReadWriteMany
该卷可以被多个节点以读/写模式挂载(所在节点不同的多个pod可以一起挂载)
rwx
ReadOnlyMany
该卷可以被多个节点以只读模式挂载
rox
如果多副本挂载一个pvc,则存储共享
命令行简写:
RWO - ReadWriteOnce
RWX - ReadWriteMany
ROX - ReadOnlyMany
Volume 插件 ReadWriteOnce ReadOnlyMany ReadWriteMany
SElasticBlockStoreAWSElasticBlockStore ✓ - -
AzureFile ✓ ✓ ✓
AzureDisk ✓ - -
CephFS ✓ ✓ ✓
Cinder ✓ - -
FC ✓ ✓ -
FlexVolume ✓ ✓ -
Flocker ✓ - -
GCEPersistentDisk ✓ ✓ -
Glusterfs ✓ ✓ ✓
HostPath ✓ - -
iSCSI ✓ ✓ -
PhotonPersistentDisk ✓ - -
Quobyte ✓ ✓ ✓
NFS ✓ ✓ ✓
RBD ✓ ✓ -
VsphereVolume ✓ - -
PortworxVolume ✓ - ✓
ScaleIO ✓ ✓ -
StorageOS ✓ - -
- 回收策略
Retain
保留,删除pvc时,pv变为release状态,pv不可用,若想用pv需删掉此pv重建,删除pv并不会删除存储的资源
Recycle
回收,基本擦除,删除pvc时,会将pv路径下的内容删掉,pv重新归为Available状态
Delete
删除,删除pvc的时候。存储资源也会删除掉
当前,只有 NFS 和 HostPath 支持回收策略。
AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略,nfs不支持删除策略
- 状态
Available
可用的,一块空闲资源还没有被任何声明绑定的pv
Bound
绑定的,已被pvc绑定的pv
Released
释放的,声明被删除,但是资源还未被集群重新声明
Failed
失败的,该卷的自动回收失败
- PV演示
apiVersion: v1
kind: PersistentVolume
metadata:
name: centos
spec:
capacity:
storage: 10Gi #pv大小
volumeMode: Filesystem #卷的类型,可以是Filesystem,也可以bloak(块)
accessModes: #pv支持的请求方式
- ReadWriteOnce #只允许一个节点可读可写
persistentVolumeReclaimPolicy: Retain #pv的回收策略
storageClassName: nfs #pv的类,可表示slow,storage等类别比如nfs是slow,ceph是storage
mountOptions: #挂载选项,可不填写
- hard
- nfsvers=4
nfs: #指定pv使用的存储
path: /data/mariadb #nfs共享路径
server: 10.0.0.14 #nfs服务器ip
- 持久化演示说明
#安装nfs服务器
$ yum -y install nfs-common nfs-utils rpcbind
$ mkdir /nfsdata
$ chmod 666 /nfsdata
$ cat > /etc/exports << EOF
/nfsdata *(rw,no_root_squash,no_all_squash,sync)
/nfsdata1 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata2 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata3 *(rw,no_root_squash,no_all_squash,sync)
EOF
$ systemctl start rpcbind && systemctl start nfs
#部署PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata
server: 192.168.2.21
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-2
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata1
server: 192.168.2.21
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-3
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata2
server: 192.168.2.21
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-4
spec:
capacity:
storage: 4Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
nfs:
path: /nfsdata3
server: 192.168.2.21
#创建服务并使用PVC
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs"
resources:
requests:
storage: 1Gi
- statefulSet
特性:
创建statfulset时先创建无头服务
pod命名规则:
pod名为statefulset名-N,N是序号名,从0开始 比如statefulset为web,那么pod为web-0 web-1
暴露方式:
pod使用无头服务暴露,域名为service_name.namespace名.svc.cluster.local
pvc命名规则:
volumeClaimTemplates.name-pod名,比如pvc模板名字为www,pod名为web-0,第一个pvc便是www-web-0
稳定网络位:
如果pod被删除,重新起来的pod会沿用之前的名字,并且,pod名有一个A记录,域名格式为:
pod名.service名
有序部署:
当Statfulset创建时,先创建一个pod,序号为0,当前一个podrunning时才会创建第二个pod。
并且在pod创建时,根据deployment定义的pvc模板自动创建pvc,也是有序部署
有序删除:
当Statfulset被删除时,它们被终止的顺序是从N-1到0
有序扩展:
当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态
9.集群调度
scheduler是k8s的调度器,主要作用是将pod调度到合适的节点,其需考虑一下问题:
1.公平:如何保证每个节点都能分配资源
2.资源利用最大化:集群里所有资源最大化使用
3.效率:大批量调度pod的速度更快
4.灵活:允许用户按需自定义配置调度
scheduler一直监听在api server上获取没有指定nodeName的pod来进行调度。对每个pod都会进行binding,表明该pod应该放在哪个节点上
调度过程:
调度分为两个部分:过滤和打分,过滤是将不符合的节点排除。然后再给剩下的节点进行打分优选,最后从中选择分数最高的节点进行调度,如果多个打分后仍是有多个node可选,则随机选择一个节点进行调度,如果中间有任何一步错误都会直接返回错误
- 过滤
PodFitsResources: 节点上剩余的资源是否满足Pod,内存和cpu是否满足requests
PodFitsHost: 如果Pod指定了NodeName,检查节点名称是否和PodName匹配
PodFitsHostPorts: 检查节点上已经使用的端口是否和Pod申请的Port冲突
PodSelectorMatches: 过滤掉和pod标签不匹配的节点
NodeDiskconflict: 检查节点的volume挂载,如果是只读挂的便和Pod冲突
- 打分
如果在预选时没有合适的节点,那么Pod将一直处于Pending状态,并且不断重试调度,直到有节点满足
如果在预选以后如果有多个节点满足预选条件,就继续进行优选过程:按照优先级对节点排序
优选是由一系列键值对组成,其中键是优选名称,值是优选的权重
LeastRequestedPriority: 通过计算节点CPU和Memory使用率决定权重,CPU和Memory使用率越小的节点权重越高
BalancedResourceAllocation: 节点的CPU和Memory使用比例越近权重越高,比如一个节点CPU10% Memory%50,就没有CPU和Memory同为%30的权重高,此优选和上面的连用,一般不会单独使用。
ImageLocalityPriority: 倾向于已有镜像的节点,镜像总大小越大,权重越高
可参阅文档: https://kubernetes.io/zh/docs/reference/scheduling/config/#multiple-profile
通过官方文档来自定义shceduler,pod可通过spec.schedulername字段选择使用某个调度器进行调度
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
9.1 指定节点调度:
- nodeName:指定node名强制调度,优先级最高
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeName: host-3 #指定node名即可,如果没有则pod将处于pending状态
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- **nodeSelector:**通过节点标签进行调度
如果使用NodeSelector,则节点挂了,则pod也会挂,如果使用亲和性软策略即可避免,软策略是尽可能的使用指定节点,如果没有就算了,我还可以用其他的。
$ kubectl get nodes --show-labels
$ kubectl label nodes host-2 gou=gaoshengnan
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
nodeSelector: #指定标签即可,如果没有则pod将处于pending状态
gou: gaoshengnan
9.2 亲和性调度
软策略和硬策略一起使用时先满足硬策略才会看软策略,多个软策略同时使用时,要增加权重
- 键值运算关系:
In: 规定标签需有指定的值
Notin: 规定标签不能有指定值
Gt: 规定标签中的值大于指定值
Lt: 规定标签中的值小于指定的值
Exists:指定的label需存在
DoesExists:指定的label不需存在
1.如果同时指定了 nodeSelector
和 nodeAffinity
,两者必须都要满足,才能将 pod 调度到候选节点上
2.如果指定了多个nodeSelectorTerms
,则如果其中一个 nodeSelectorTerms
满足的话,pod将可以调度到节点上。
3.如果指定了多个 matchExpressions
,则只有当所有 matchExpressions
满足的话,pod 才会可以调度到节点上。
4.如果matchExpressions下的key
values
指定了多个,则必须都满足
- 节点亲和性 nodeAffinity
pod.spec.affinity.nodeAffinity, 强调Pod要调度哪个节点,需要节点的某标签
- requiredDuringSchedulingIgnoredDuringExecution (硬策略)
: 必须满足条件
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nodeAffinity
name: nodeaffinity
spec:
replicas: 1
selector:
matchLabels:
app: nodeaffinity
template:
metadata:
labels:
app: nodeaffinity
spec:
containers:
- image: nginx
name: nginx
affinity: #亲和性
nodeAffinity: #Node亲和性
requiredDuringSchedulingIgnoredDuringExecution: #硬策略
nodeSelectorTerms: #Node亲和性方案
- matchExpressions:
- key: kubernetes.io/hostname
values:
- host-2
operator: In #键值对运算,这代表标签为kubernetes.io/hostname里必须有k8s-node1值
- preferredDuringSchedulingIgnoredDuringExecution (软策略)
符合策略就去执行,不符合就执行默认调度;
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nodeAffinity
name: nodeaffinity
spec:
replicas: 1
selector:
matchLabels:
app: nodeaffinity
template:
metadata:
labels:
app: nodeaffinity
spec:
containers:
- image: nginx
name: nginx
affinity: #亲和性
nodeAffinity: #Node亲和性
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 #多个软策略设置权重,权重范围为1-100,多个软亲和满足条件,按权重调度
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- host-2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 2 #此权重比上面的大,则优先满足权重更高的调度
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- host-3
- 节点软硬亲和度
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nodeAffinity
name: nodeaffinity
spec:
replicas: 1
selector:
matchLabels:
app: nodeaffinity
template:
metadata:
labels:
app: nodeaffinity
spec:
containers:
- image: nginx
name: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
values:
- host-2
operator: In
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- host-3
- Pod亲和性 podAffinity
解决pod可以和哪些pod部署在同一个节点里面
根据在节点上正在运行的pod的标签而不是节点的标签进行判断和调度,要求对节点和pod两个条件进行匹配。
#先创建一个pod,标签是app: nginx
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
#创建带有亲和性的deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nodeAffinity
name: nodeaffinity
spec:
replicas: 1
selector:
matchLabels:
app: nodeaffinity
template:
metadata:
labels:
app: nodeaffinity
spec:
containers:
- image: nginx
name: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx #Pod的标签为app=nginx
topologyKey: kubernetes.io/hostname #拓扑域,通过此键判断pod在哪个节点上,一个域可有多个节点
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
values:
- nginx
operator: NotIn
topologyKey: kubernetes.io/hostname
#运行后,pod会找到app=nginx标签的pod,然后通过拓扑域指定的节点的标签,将该pod调度到拥有app=nginx标签的pod所在节点上。
- Pod反亲和
pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- bj
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
#此时两个节点都有 zone=bj的标签,运行后表示nginx只能放置在标签为zone=bj的node上;另外,尽量放在pod没有标签app=nginx的节点(通俗的说,一个节点尽量不要放两个nginx)
9.3 污点和容忍
Taint与Toleration
Taint和Toleration相互配合使用,可以避免Pod被调度到不合适的节点,每个节点都可应用多个Tanit,这代表不能容忍Taint的Pod不可以在节点上运行。如果将Toleration应用到Pod,则表示Pod可以容忍污点,便可调度到具有匹配的污点的节点上(不是强制)
- 污点(Taint)
- 污点组成
key=value:effect
- 每个污点都有一个Key和Value作为污点的标签,Value可以为空,effect是指定污点的策略,目前支持如下
NoSchedule: 表示不能有Pod调度到具有该污点的节点上
PreferNoSchedule: 尽可能不要调度到具有该污点的节点上
NoExecute: 不仅不让Pod来调度,还把节点上的其他Pod也给驱逐掉
- 污点设置、查看和去除
# 设置污点
kubectl taint nodes host-2 key1=value1:NoSchedule
# 节点说明中,查找Taints字段
kubectl describe node host-1
# 去除污点
kubectl taint nodes host-2 key1=value1:NoSchedule-
- 容忍 (Toleration)
设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的node上
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- bj
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
tolerations:
- key: "app"
value: "nginx"
effect: "NoExecute"
operator: "Equal"
tolerationSeconds: 3600
tolerations
下的key
,value
,effect
要和污点一致,其中tolerationSeconds
代表node为NoExecute
的污点效果时,允许pod可运行时间,如果不指定,那么便一直在node上运行
operator的默认值是
Equal,如果指定的是
Equal,那么容忍和污点的
key`要保持一直,表示可以容忍污点
如果设定为Exists
那么容忍不能指定value
值
设定Exists
的两种情况:
如果key
为空,表示pod可容忍所有的污点
如果effect
为空,则pod可容忍指定污点的污点效果
10.集群安全
kubernetes是一个分布式集群管理工具,保证其安全性是非常重要的,Api Server是集群内部各个组件的通信中介,也是外部控制的入口,所以kubernetes的安全机制基本就是围绕保护API Server来设计的。kubernetes使用了认证(Authentication)、鉴权(Authorization)、准入控制(AdmissionControl)三步来保证API Server的安全
10.1 认证
- Http Token
通过Token来识别合法用户,token是一串很长的特殊编码的字符串,每个token对应一个用户名。存放在了API Server能访问的文件中
客户端发起API请求时,需在HTTP Header里放入Token,API Server收到请求后会查看Header里是否有Token,如果有会对比文件中的Token,识别用户是哪个用户就拥有哪个用户的权限。
因为其Token不是在etcd里而是个文件中,所以安全性较低。
- Http Base
用户名+密码,密码采用bash64算法进行编排后放到HTTP Requests中的Header中的Authorization 域里发送给服务端,服务端收到后进行编码,获取用户名及密码和集群里进行比对
因为密码是base64方式加密,所以安全性也比较低。
- Https证书认证
https双向认证,服务端验证客户端是否合法,客户端也会验证服务端是否为请求的服务端(企业多数选择)
1.服务端和客户端向当前kubernetes中的ca申请证书,ca再下发证书
2.当客户端访问服务端的时候会将证书发给服务端,服务端也将证书发给客户端来验证
3.验证通过后,客户端和服务端通过随机密钥来进行通信
需要认证的组件
kubernetes组件对APi Server的访问:Kubectl,Controller Manager,Scheduler,Kubelet,kube-proxy
kubernetes管理的Pod对容器的访问:Pod(dashboard也是以Pod形式)controller manager以及scheduler与API Server在一个节点上,所以直接使用API Server的非安全端口访问,访问127.0.0.1:6443即可
kubectl kubelet,kube-proxy访问API Server时都是远程访问,所以需要HTTPS双向认证
证书颁发
手动颁发:通过kubernetes内部的ca进行签证证书
自动颁发:kubectl第一次连接服务端时使用Token连接,通过后 Controller Manager会为kubelet生成一个证书,以后便使用证书认证(kubeadm方式部署,都是用的自动颁发)
kubeconfig
kubeconfig文件包含集群参数(ca证书,APi server地址+端口),集群context信息(集群名称,用户名)客户端参数
(上面生成的证书和私钥),kubernetes的组件启动时指定不同的Kubeconfig文件可以切换到不同的集群
10.1.1 ServiceAccount
pod中的容器访问API Server所使用的,因为Pod的创建删除都是动态的,像组件一样给需要访问API Server 的 Pod证书以后,Pod删除了,证书就废了,十分浪费集群资源,所以有了Service Account,Pod可以使用此来循环认证,SA实际也是一组文件,包含了私钥,命名空间等重要信息,相当于Pod的用户。
Secret与sa的关系:
Secret有一种类型是Service Account,在创建sa的时候会自动创建一个secret来为sa做加密,每个命名空间都有一个默认的sa和默认的secret,如果pod在运行时未指定sa,则pod使用默认的sa,pod会通过secret将sa挂载到pod的/run/secret/kubenetest.io/serviceaccount目录下
secret挂载了三个文件:namespcae、Token、ca.crt
namespace: 是pod所在的命名空间,标识这个sa作用在哪个命名空间中
Token: 是使用API Server签名的JWT。用于访问APi Server时,Server端认证
ca.crt: 根证书,用于Client端验证APi Server发送的证书
本机组件直接使用127.0.0.1访问,其他远程组件需要https双向认证;pod访问需要使用SA去认证,SA通过secret挂载到pod中
10.2 鉴权
上面认证的过程,只是确认双方可以通信。而鉴权是确定请求方有哪些资源的权限,API Server目前支持以下鉴权策略:(可通过 API启动参数 "–authorization-mode"来指定鉴权策略)
AlwaysDeny:表示拒绝所有的请求,一般用于测试
AlwaysAllow:允许接收 所有请求,如果集群不需要鉴权流程,则可以采用该策略
ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的鉴权规则对用户请求进行匹配和控制 (修改后需重新启动API才可以生效)
Webbook:通过调用外部 REST 服务对用户进行鉴权(内部集群中无法使用kubectl进行管理)
RBAC(Role-Based Access Control):基于角色的访问控制,现行默认规则(1.15版本开始采用,现在已经是默认使用此策略)
- RBAC 授权模式
RBAC(Role-Based Access Control)基于角色的访问控制,在 Kubernetes 1.5 中引入,现行版本成为默认标
准。相对其它访问控制方式,拥有以下优势
- 对整个集群的资源和非资源覆盖 #资源是Pod,Deploy,内存,cpu,非资源是一些元数据信息,比如pod状态
基本将集群的所有都覆盖了
-
整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作
-
可以在运行时调整,无需重启API
RBAC的API资源对象说明:
RBAC引入了四个顶级对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding四种对象,均可通过kubectl和API进行操作
Role and ClusterRole
在RBAC API中,Role表示一组规则权限,权限是累加形式,也就是说开始没有任何权限,加什么权限有什么权限,不会
出现上了Role有一堆权限,然后删除权限!Role绑定与一个namespace,若想跨namespace,使用ClusterRole。
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
namespace: test #创建在哪个命名空间
name: pod-reader
rules:
- apiGroups: [""] #代表赋予pod-reader的组和版本,如过为空代表core核心组
resources: ["pods"] #对象是Pod
verbs: ["get","watch","list"] #动作,获取,监听。列出,也就是拥有get Pod的详细信息权限,以及获取,监听
ClusterRole拥有和Role相同的权限角色能力,只是ClutserRole作用于整个集群,ClusterRole可以用于:
- 集群级别的资源访问:比如node访问权限
- 非资源类型:比如endpoint
- 所有命名空间下的资源控制:比如Pod
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""] #代表赋予pod-reader的组和版本,如过为空代表core核心组
resources: ["secret"] #对象是Pod
verbs: ["get","watch","list"] #动作,获取,监听。列出,也就是拥有get Pod的详细信息权限,以及获取,监听
#查看当前命名空间下的角色
kubectl get role
#查看集群角色
kubectl get clusterrole | grep xx
#命令方式创建role
kubectl create role read-pod --verb=get --verb=watch --verb=list --resource=pod --dry-run -o yaml > role.yaml
#常见使用方式
# 允许读/写在 "extensions" 和 "apps" API 组中的 "deployments" 资源:
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 允许读取 "pods" 和读/写 "jobs" :
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch", "extensions"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
RoleBinding and ClusterRoleBinding:
RoleBinding可以将定义好权限的角色绑定给一组对象(subjects),subejects里包含User,Group,Service Account。RoleBinding可以绑定一个Role,也可以绑定一个ClusterRole给用户等,而ClusterRoleBinding只能绑定ClusterRole
将test命名空间的pod-reader Role授予tom用户,此时tom在test命名空间拥有了pod-reader权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pod #RoleBinding的名字
namespcae: test #绑定给test命名空间
subjects: #对象
- kind: User #对象类型
name: Tom #用户的名字
apiGroup: rbac.authorization.k8s.io #如果绑定的是sa,则该字段不可写
roleRef:
kind: Role #绑定类型为角色
name: read-pod #绑定的角色名
apiGroup: rbac.authorization.k8s.io
Rolebinding也可以引用ClusterRole来对当前namespace内的用户、用户组、SA进行绑定,这种操作允许管理员创建一些通用的ClusterRole,然后在不同的namespace里使用
如果集群中有多个namespace分配给不同的管理员,每个namespace的权限是一样的,就可以只定义一个clusterrole,然后通过rolebinding将不同的namespace绑定到管理员身上,否则就需要每个namespace定义一个Role,然后做一次rolebinding
例如以下RoleBinding引用了一个ClusterRole,这个ClusterRole拥有访问集群内的secret的访问权限,但是授权给用户jerry只能在default的namespace里使用:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: secret-read
namespace: default
subjects:
- kind: User
name: jerry
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: read-secret
apiGroup: rbac.authorization.k8s.io
#查看roleBinding的详细信息
kubectl get rolebinding -o wide -n default
NAME AGE ROLE USERS GROUPS SERVICEACCOUNTS
secret-read 39s ClusterRole/read-secret jerry
roleBinding名 创建时间 绑定的角色 绑定给的对象
#命令方式创建rolebinding
kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
对资源引用方式(resources):
Kubernetes集群内一些资源是以字符串表示的,这些字符串会在API的URL地址中出现,同时某些资源会包含子资源,例如logs资源就属于Pods的子资源,API的样例:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
子资源:
在RBAC鉴权模式下控制这些子资源的访问权限,可以通过/分隔符来实现,以下是对Pod的子资源logs进行控制样例:
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: pod-logs
namespace: default
rules:
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list"]
对主体引用方式(subject):
RoleBinding和ClusterRoleBinding绑定给Subjects,Subjects可以是user,groups,service accounts
subjects中的User是使用字符串去表示,可以是普通字符串,数字,甚至使用邮箱也可以,但user的前缀system: 是系统保留的,确保普通用户不会使用此前缀。
Groups书写格式和Users相同,都为一串字符串,且system:前缀同样是系统保留
常见引用主体方式:
用户的名称为 “alice@example.com”:
subjects:
- kind: User
name: "alice@example.com"
apiGroup: rbac.authorization.k8s.io
组的名称为 “frontend-admins”:
subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
服务账号在 kube-system 命名空间中:
subjects:
- kind: ServiceAccount
name: default
namespace: kube-system
在名称为 “qa” 命名空间中所有的服务账号:
subjects:
- kind: Group
name: system:serviceaccounts:qa
apiGroup: rbac.authorization.k8s.io
所有的服务账号:
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
所有认证过的用户 (版本 1.5+):
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
所有未认证的用户 (版本 1.5+):
subjects:
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
所有用户 (版本 1.5+):
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
默认的role和clusterRole:
cluster-admin | system:masters 组 | 允许超级用户在平台上的任何资源的所有操作。 当在 ClusterRoleBinding 中使用时,可以授权对集群中以及所有命名空间中的全部资源进行完全控制。 当在 RoleBinding 中使用时,可以授权控制 RoleBinding 所在命名空间中的所有资源,包括命名空间本身。 |
---|---|---|
admin | 无 | 允许管理员访问权限,旨在使用 RoleBinding 在命名空间内执行授权。 如果在 RoleBinding 中使用,则可授予对命名空间中的大多数资源的读/写权限, 包括创建角色和绑定角色(RoleBinding)的能力。 但是它不允许对资源配额或者命名空间本身进行写操作。 |
edit | 无 | 允许对命名空间的大多数对象进行读/写操作。 它不允许查看或者修改角色(Roles)或者角色绑定(RoleBindings)。 |
view | 无 | 允许对命名空间的大多数对象有只读权限。 它不允许查看角色(Roles)或角色绑定(RoleBindings)。 它不允许查看 Secrets,因为这类操作属于越权。 |
实验:
# 创建用户并设置密码
$ useradd tom
$ echo 123.com | passwd --stdin tom
# 书写用户的证书
vim tom.json
{
"CN": "tom",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "HangZhou",
"L": "XS",
"O": "k8s",
"OU": "System"
}
]
}
# 安装证书生成工具
$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ mv cfssl_linux-amd64 /usr/local/bin/cfssl
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
$ wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
$ mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
# 生成证书
cd /etc/kubernetes/pki #此目录存放了密钥信息
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /root/install-k8s/cert/tom/tom.json | cfssljson -bare tom
-ca: ca的证书
-ca-key 私钥
-profile 创建信息
-bare 输出格式
ls
tom.pem tom-key.pem
#设定集群参数
cd /root/install-k8s/cert/tom
export KUBE_apiServer="https://192.168.2.100:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_apiServer} \
--kubeconfig=tom.kubeconfig
#设置客户端参数
kubectl config set-credentials tom \
--client-certificate=/etc/kubernetes/pki/tom.pem \
--client-key=/etc/kubernetes/pki/tom-key.pem \
--embed-certs=true \
--kubeconfig=tom.kubeconfig
#设置上下文参数(绑定到哪个空间)
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=tom \
--namespace=tom \
--kubeconfig=tom.kubeconfig
$ kubectl create namespace tom
#创建RoleBinding,将集群角色admin绑定给tom用户,作用于tom命名空间
kubectl create rolebinding tom-admin --clusterrole=admin --user=tom --namespace=tom
su - tom
mkdir .kube
exit
cp /root/sec/cert/tom/tom.kubeconfig /home/tom/.kube/
chown tom.tom /home/tom/.kube/tom.kubeconfig
su - tom
cd .kube
mv tom.kubeconfig config
#切换上下文:
kubectl config use-context kubernetes --kubeconfig=/home/tom/.kube/config
su - tom
kubectl get pod #至此授权完毕
准入控制:
准入控制是API Server的插件集合,通过添加不同的插件,实现不同的准入控制规则。甚至于API Server的一些主
要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的 1.19 的推荐列表是:
NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota
列举几个插件的功能:
NamespaceLifecycle: 防止在不存在的 namespace 上创建对象,防止删除系统预置 namespace,删除namespace 时,连带删除它的所有资源对象。
LimitRanger:确保请求的资源不会超过资源所在 Namespace 的 LimitRange 的限制。
ServiceAccount: 实现了自动化添加 ServiceAccount。
ResourceQuota:确保请求的资源不会超过资源的 ResourceQuota 限制。
11.HelmV2版本及其功能
Helm通过打包的方式,支持发布的版本管理和控制,简化了k8s应用部署和管理
Helm的本质是让k8s的应用deployment,service等)可配置,能动态生成。
它是通过动态生成k8s资源清单(deployment.yaml,service.yaml),然后再调用kubectl自动执行k8s资源部署实现的。
- 两个重要概念
-
chart是创建一个应用的信息集合,包括各种kubernetes对象的配置模板,参数定义、依赖关系、文档说明等。
chart是应用部署的自包含逻辑单元。可以将chart想象成yum中的软件包
-
release 是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成
一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release
在docker中,将应用程序或者说整个运行环境封装成镜像,通过运行镜像,生成容器
在k8s中,Helm把集群的部署方案写入到chart里,通过chart部署集群,生成对应的release
11.2 自建chart
#创建文件夹
$ mkdir ./hello-world
$ cd ./hello-world
#创建自描述文件:Chart.yaml,此文件必须存在,且文件内必须有name和version字段,注意,C是大写
$ vim Chart.yaml
name: hello-word
version: 1.0.0
#创建模板文件,用于生成Kubernetes 资源清单
$ mkdir ./templates #必须是templates目录,这是固定格式
$ cd templates
$ vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
name: helm-hello-word
spec:
replicas: 1
selector:
matchLabels:
app: helm-hello-word
template:
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
spec:
containers:
- image: nginx
name: nginx
# 使用命令 helm install RELATIVE_PATH_TO_CHART 创建一次Release
$ helm install --name hello-word .
# 查看release信息
$ helm ls
# 通过kubectl查看
$ kubectl get pod
- values文件
定义整个template的全局变量
通过更改values文件即可达成更改deployment,svc等资源清单的目的
#像image,repository都可以随便写,然后deployment引用的时候一致即可,
#更改某个参数时,只需更改values然后使用helm upgrade release_name即可实现
#创建values
vim hello-word/values.yaml
image:
repository: nginx
tag: "v1"
#创建deployment的资源清单
vim hello-word/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
name: helm-hello-word
spec:
replicas: 1
selector:
matchLabels:
app: helm-hello-word
template:
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
spec:
containers:
- image: {{ .Values.image.repository }}:{{ .Values.image.tag}}
imagePullPolicy: IfNotPresent
name: nginx
#创建service的资源清单
vim hello-word/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
name: helm-hello-word
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: helm-hello-word
type: NodePort
status:
loadBalancer: {}
#安装chart,生成release
helm install --name test .
curl验证
#修改values的参数
vim hello-word/values.yaml
image:
repository: nginx
tag: "1.8.1"
#更新release
helm upgrade test .
curl 验证
- helm版本更新
vim configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-word-helm
data:
index.html: |
this is hello-word-helm
thank you listening
#在上面的deployment增加以下字段:
volumeMounts:
- name: hello-word-helm
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: hello-word-helm
configMap:
name: hello-word-helm
#更新,会触发重新部署
helm upgrade hello-word-helm .
#查看版本信息
helm histroy hello-word-helm
11.3 基本命令
#安装Chart 生成release
helm install --name release_name --namespace namespace_name
-f #-f的意思是指定values文件
--version number #指定版本
#尝试安装
hlem install --name release_name --dry-run
--dry-run #测试运行,并不会真正的运行
#查看release信息
helm list
helm ls
helm ls -a #可查看到已停用的release版本
#helm更新
helm upgrade release_name .
#可查看到当前release版本信息
helm list
helm ls
#查看历史信息
helm history release_name
#回滚helm
helm rollback --debug release_name 版本号
#查看状态
kubectl get pod
helm status release_name
#删除release
helm delete release_name
此命令在使用后对象如pod,deployment,撒都会被删除,但是release版本还会存在,类似rs更新一样,可以再次激活
可使用helm rollback release_name 版本号激活
#删除release历史版本:
helm delete --purge relsase_name --purge会删除掉历史版本
#调试:使用--dry-run --debug会打印出清单内容,但并不会真的执行
helm install --name release_name . --dry-run --debug --set image.tag=latest
#更新仓库(类似于yum仓库)
helm update repo
#查看仓库
helm repo list
#增加repo仓库
helm repo add repo_name xxx
#删除repo仓库
helm repo remove repo_name
#将Chart下载到本地
helm fetch chart_name [--version]
#搜索应用,会根据指定的repo,搜索其下所有包
helm search repo <repo_name>
#根据输入的包在配置的所有仓库中搜索
helm search repo <app_name>
#查看release状态
helm status release_name
12.HelmV3版本及其功能:
- 去掉Tiller服务端,不再使用Tiller来连接集群
- release支持不同命名空间中重复使用
- 可以将Chart推送到docker镜像仓库
V3版本当作使用Helm Client端直接通过kubeconfig,然后kubeconfig连接kube-apiServer,由kube-apiServer创建应用
- 两个重要概念
-
chart是创建一个应用的信息集合,包括各种kubernetes对象的配置模板,参数定义、依赖关系、文档说明等。
chart是应用部署的自包含逻辑单元。可以将chart想象成yum中的软件包
-
release 是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成
一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release
在docker中,将应用程序或者说整个运行环境封装成镜像,通过运行镜像,生成容器
在k8s中,Helm把集群的部署方案写入到chart里,通过chart部署集群,生成对应的release
安装
tar -xzvf helm-v3.3.1-linux-amd64.tar.gz
cp linux-amd64/helm /usr/local/bin
helm version
配置helm仓库
#增加微软helm仓库,默认仓库有墙,这个仓库传输速度快,且和官方版本保持一致
helm repo add stable http://mirror.azure.cn/kubernetes/charts/
#查看
helm repo list
12.1 自建chart
#创建chart模板
helm create hello-word
#修改模板
cd hello-word/templates
rm -rf *
kubectl create deployment web --image=nginx --dry-run -o yaml > deployment.yaml
kubectl create service clusterip web --tcp=80:80 --dry-run -o yaml > serviece.yaml
#安装hello-word
cd hello-word
helm install hello-word .
#查看
helm ls
kubectl get pod
#验证
kubectl get svc
curl
- values文件
定义整个template的全局变量
通过更改values文件即可达成更改deployment,svc等资源清单的目的
#像image,repository都可以随便写,然后deployment引用的时候一致即可,
#更改某个参数时,只需更改values然后使用helm upgrade release_name即可实现
#创建values
$ vim hello-word/values.yaml
image: nginx
tag: 1.8.1
#创建deployment的资源清单
$ vim hello-word/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
name: helm-hello-word
spec:
replicas: 1
selector:
matchLabels:
app: helm-hello-word
template:
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
spec:
containers:
- image: {{ .Values.image}}:{{ .Values.tag}}
imagePullPolicy: IfNotPresent
name: nginx
#创建service的资源清单
vim hello-word/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: helm-hello-word
name: helm-hello-word
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: helm-hello-word
type: NodePort
status:
loadBalancer: {}
#更新release
helm upgrade hello .
curl 验证
12.2 基本命令
#安装Chart 生成release
helm install release_name --namespace namespace_name
-f #-f的意思是指定values文件
--version number #指定版本
#尝试安装
hlem install release_name --dry-run
--dry-run #测试运行,并不会真正的运行
#查看release信息
helm list
helm ls
helm ls -a #可查看到已停用的release版本
#列出helm变量渲染后yaml
helm template .
#helm更新
helm upgrade release_name .
#可查看到当前release版本信息
helm list
helm ls
#查看历史信息
helm history release_name
#回滚helm
helm rollback --debug release_name 版本号
#查看状态
kubectl get pod
helm status release_name
#删除release
helm delete release_name
此命令在使用后对象如pod,deployment都会被删除,并且历史版本也不保留,全部删除
#调试:使用--dry-run --debug会打印出清单内容,但并不会真的执行
helm install release_name . --dry-run --debug --set image.tag=latest
#更新仓库(类似于yum仓库)
helm update repo
#查看仓库
helm repo list
#增加repo仓库
helm repo add repo_name xxx
#删除repo仓库
helm repo remove repo_name
#将Chart下载到本地
helm pull chart_name [--version]
#创建chart模板
helm create chart_name
#搜索应用,会根据指定的repo,搜索其下所有包
helm search repo <repo_name>
#根据输入的包在配置的所有仓库中搜索
helm search repo <app_name>
#查看搜索出来的Chart信息
helm show chart <repo/app>
#查看release状态
helm status release_name
更多推荐
所有评论(0)