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)
  1. Flannel

让集群的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。而且它还能够在这些IP地址之间建立一个覆盖网络(overlayNetwork),通过这个覆盖网络将数据包原封不动的传递到对应的目标容器内。

Flannel相当于一个守护进程,它会监听一个端口,这个端口就是后续进行数据转发和数据接受的一个服务端口,如果Flannel成功启动,它就会开启一个Flannel0 的一个网桥,这个网桥专门去收集Docker0转发出来的数据包,可以理解为一个钩子函数;

Flanneld这里会有一堆的路由表信息,它是存储在etcd中由Flannel去自动拉取的,不同Pod间的通信就需要这些路由表来确定具体的转发路径;

etcd对Flannel提供如下说明
1、存储管理Flannel可分配的IP地址段资源;
2、监控ETCD中每个Pod的实际地址,并在内存中维护Pod节点路由表

通讯过程

在这里插入图片描述

  1. app1将自身IP地址、目标IP及其所发数据发送至Docker0的网桥;
  2. Docker0获取到发送的数据包,由于目标IP的网段与当前Docker0的网段不是同一个,所以它会通过钩子函数抓取数据信息继续发送至Flannel0的网桥
  3. Flannel0网桥这时候会通过Flanneld中的路由表信息来确定具体的转发路径,此时会进行一个数据的二次封装,然后通过对应的外部节点IP(192.168.66.11/24)发送到目标外部IP(192.168.66.12/24)
  4. 发送到Node2节点之后会对数据包进行解析获取具体目标Pod的IP(10.1.20.3/24),然后发送到Backend从而完成整个Pod通信
  • pod与service之间的通信

使用各节点的IPtables规则来进行网络通信

  1. Pod到外网:Pod向外网发送请求,查找路由表,转发数据包到宿主机的网卡,宿主网卡完成路由选择后,IPtables执行Masquerade,把源IP修改为宿主网卡的IP,然后向外网服务器发送请求;
  2. 外网访问Pod:通过service来访问,一般使用NodePort;

4.3 pod生命周期

img

  • 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 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
  1. init容器总是运行到成功完成为止
  2. 每个init容器必须成功完成才会 运行下一个init容器
  3. 如果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,则诊断被认为是成功的。

每次探测都将获得以下三种结果之一:

  • 成功:容器通过了诊断。
  • 失败:容器未通过诊断。
  • 未知:诊断失败,因此不会采取任何行动。
  1. livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。
  2. 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 资源类型

  • 名称空间级别:
  1. 工作负载型:Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob
  2. 服务发现及负载均衡:Service、ingress
  3. 配置与存储型:Volume(存储卷)、CSI(容器存储接口)
  4. 特殊类型的存储卷: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 并创建一个新的来替换

  1. 定义deployment来创建RS管理Pod
  2. 滚动升级和回滚应用
  3. 扩容和缩容
  4. 暂停和继续
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成功结束

  1. template格式同Pod
  2. RestartPolicy仅支持Never或OnFailure
  3. 单个Pod时,默认Pod成功运行后Job即结束
  4. .spec.completions标志Job结束需要成功运行的Pod个数。默认为1
  5. .spec.parallelism标志并行运行的Pod个数,默认为1
  6. 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,即 : * * * * *

  1. 在给定的时间调度Job运行

  2. 创建周期性运行的Job,例如:数据库备份、发送邮件

  3. .spec.schedule:调度,必须字段,指定任务运行周期

  4. .spec.jobTemplate:job模板,必须字段,指定需要运行的任务,格式同Job

  5. .spec.startingDeadlineSeconds:启动job的期限(秒级别),Job运行时间超过后,会被认为是失败的

  6. .spec.concurrencyPolicy:并发策略

    ​ Allow:允许并发运行Job

    ​ Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个

    ​ Replace:取消当前正在运行的Job,用一个新的来替换

  7. .spec.supend:挂起后续的Job true false

  8. .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种类型
  1. 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
    
  2. 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
  1. LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。

  2. 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.如果同时指定了 nodeSelectornodeAffinity两者必须都要满足,才能将 pod 调度到候选节点上

​ 2.如果指定了多个nodeSelectorTerms,则如果其中一个 nodeSelectorTerms 满足的话,pod将可以调度到节点上。

​ 3.如果指定了多个 matchExpressions,则只有当所有 matchExpressions 满足的话,pod 才会可以调度到节点上。

​ 4.如果matchExpressions下的key values指定了多个,则必须都满足

  1. 节点亲和性 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
  1. 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所在节点上。
  1. 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)
  1. 污点组成
key=value:effect
  1. 每个污点都有一个Key和Value作为污点的标签,Value可以为空,effect是指定污点的策略,目前支持如下
NoSchedule:			表示不能有Pod调度到具有该污点的节点上
PreferNoSchedule:	尽可能不要调度到具有该污点的节点上
NoExecute:			不仅不让Pod来调度,还把节点上的其他Pod也给驱逐掉
  1. 污点设置、查看和去除
# 设置污点
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下的keyvalueeffect要和污点一致,其中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 中引入,现行版本成为默认标
准。相对其它访问控制方式,拥有以下优势

  1. 对整个集群的资源和非资源覆盖 #资源是Pod,Deploy,内存,cpu,非资源是一些元数据信息,比如pod状态

基本将集群的所有都覆盖了

  1. 整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作

  2. 可以在运行时调整,无需重启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-adminsystem: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资源部署实现的。

  • 两个重要概念
  1. chart是创建一个应用的信息集合,包括各种kubernetes对象的配置模板,参数定义、依赖关系、文档说明等。

    chart是应用部署的自包含逻辑单元。可以将chart想象成yum中的软件包

  2. 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版本及其功能:

  1. 去掉Tiller服务端,不再使用Tiller来连接集群
  2. release支持不同命名空间中重复使用
  3. 可以将Chart推送到docker镜像仓库

V3版本当作使用Helm Client端直接通过kubeconfig,然后kubeconfig连接kube-apiServer,由kube-apiServer创建应用

  • 两个重要概念
  1. chart是创建一个应用的信息集合,包括各种kubernetes对象的配置模板,参数定义、依赖关系、文档说明等。

    chart是应用部署的自包含逻辑单元。可以将chart想象成yum中的软件包

  2. 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
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐