k8s伸缩与亲和

[toc]

一、HPA与弹性伸缩

1.1 scale

  • scale命令可以使用命令行通过控制器调整副本数
kubectl scale --replicas=3 deployment/mysql -n default

1.2 HPA

1.2.1 HPA简介

HPA(Horizontal Pod Autoscaler)控制器,通过autoscale自动控制在k8s集群中运行的pod数量(水平自动伸缩),需要提前设置pod范围及触发条件;k8从1.1版本开始增加了HPA控制器,用于实现基于pod中资源(CPU)利用率进行对pod的自动扩缩容功能的实现,开始版本只能基于Heapster组件实现对CPU利用率作为触发条件,但是在k8s 1.11版本开始使用Metric Server完成数据采集,然后将采集到的数据通过API(Aggregated API,汇总API),例如metrics.k8s.io、custom.Metrics.k8s.io、external.metric.k8s.io,然后再把数据提供给HPA控制器进行查询,实现基于某个资源利用率对pod进行扩缩容的目的。

控制管理器默认每隔15s(可以通过 horizontal-pod-autoscaler-sync-period修改)

kube-controller-manager --help | grep horizontal-pod-autoscaler-sync-period 进行查看

HPA控制器访问metrics-server查到的;kubelet将pod的资源利用率数据收集后,汇报给api-server,api-server将数据写入etcd中,然后metrics-server通过api-server拿到数据

1.2.2 计算公式

  • 官网案例

从最基本的角度来看,Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例。

期望副本数 = ceil[当前副本数 * (当前指标/期望指标)]

例如,当前度量值为 200m,目标设定值为 100m,那么由于 200.0/100.0 == 2.0, 副本数量将会翻倍。 如果当前指标为 50m,副本数量将会减半,因为50.0/100.0 == 0.5。 如果计算出的扩缩比例接近 1.0 (根据--horizontal-pod-autoscaler-tolerance 参数全局配置的容忍值,默认为 0.1), 将会放弃本次扩缩。

1.2.3 伸缩命令

  • 命令行
kubectl autoscale rc foo --max=5 --cpu-percent=80
  • yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  namespace: linux
  name: tomcat-app1-podautoscaler
  labels:
    app: tomcat-app1
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: tomcat-app1-deployment
  minReplicas: 2
  maxReplicas: 5
  targetCPUUtilizationPercentage: 50

1.2.4 部署hpa

  • 通过yaml部署
 kubectl apply -f hpa.yaml

首次启动,默认是等5分钟,开始伸缩;可以设置冷却期,防止pod刚扩缩容后,又马上恢复

二、CI/CD

2.1 CI

CI(Continuous Integration)持续集成

2.1.1 gitlab简介

https://about.gitlab.com/

GitLab是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务

GitLab和GitHub一样属于第三方基于Git开发的产品,免费且开源(基于MIT协议),与GitHub类似,可以注册用户,任意提交你的代码,添加SSHKey等;不同的是,GitLab是可以部署到自己的服务器上,数据库等一切信息都掌握在自己手上,适合团队内部写作开发

简单来说可以把GitLab看作个人版的GitHub

2.1.2 安装gitlab

  • 安装相关依赖
yum install -y policycoreutils openssh-server opssh-clients postfix
  • 关闭防火墙并设置开机不启动
systemctl disable firewalld
systemctl stop firewalld
  • 启动ssh服务并设置为开机自启动
systemctl enable sshd
systemctl start sshd
  • 启动postfix服务并设置为开机自动
systemctl enable postfix
systemctl start postfix
  • 下载gitlab包,并安装
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
rpm -ivh gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
  • 修改gitlab配置
vim /etc/gitlab/gitlab.rb

修改gitlab访问地址和端口,默认为80

external_url 'http://IP:PORT'

nginx['listen_port'] = PORT

  • 重载配置及启动gitlab
gitlab-ctl reconfigure
gitlab-ctl restart

2.1.3 组、项目和用户

  • 创建组

使用管理员root创建组,一个组里面可以有多个项目分支,可以将开发添加到组里面进行权限设置,不通的组就是公司里不通的开发项目或者服务模块,不通的组添加不通的角色即可实现对开发成员权限的管理

1646185133776.png

私有组,只有组里的用户才可以访问;公开的组所有人都可以访问;通常设置为私有

  • 创建项目
1646185342798.png

在上步创建的组中创建项目,图中标红方框位置,选择刚才创建的组,创建私有项目

  • 创建用户

点击导航栏扳手图标(Admin Area),点击Users

1646185877988.png

点击New user

1646186020335.png

密码会在用户第一次登陆时重置

1646186095509.png

项目限制,默认是十万个,可以自己修改;访问级别默认是Regular,可以访问归属组和项目,Admin可以访问所有组、项目和用户

创建用户后点击Edit设置用户密码

1646186348591.png
1646186389583.png
  • 添加用户到组

点击导航栏Groups,Explore groups

1646186508814.png

点击进去要管理的项目,点击Members

1646186615114.png

选择用户和相应的权限添加到组

1646186796939.png

GitLab用户在组里面有五种不同权限:

Guest:可以创建issue、发表评论、不能读写版本库

Reporter:可以克隆代码,不能提交;QA、PM可以赋予这个权限

Developer:可以克隆代码、开发、提交、push;普通开发可以赋予这个权限

Maintainer:可以创建项目、添加tag、保护分支、添加项目成员、编辑项目;核心开发可以赋予这个权限

Owner:可以设置访问权限(Visibility Level)、删除项目、迁移项目、管理组成员;开发组组长可以赋予这个权限

2.2 CD

CD(Continuous Delivery)持续交付

2.2.1 jenkins简介

Jenkins是一个开源软件项目,是基于java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开发易用的软件平台,是软件项目可以进行持续集成。

功能包括:

持续的软件版本发布/测试项目

监控外部调用执行的工作

2.2.2 安装jenkins

  • 安装jdk依赖
yum install -y java-1.8.0-openjdk*

安装后目录为/usr/lib/jvm

  • 关闭防火墙并设置开机不启动
systemctl disable firewalld
systemctl stop firewalld
  • 安装jenkins
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/jenkins-2.300-1.1.noarch.rpm
rmp -ivh jenkins-2.300-1.1.noarch.rpm
  • 修改jenkins配置
vim /etc/sysconfig/jenkins

JENKINS_USER="root"

默认是jenkins用户,需要创建一个jenkins用户,用root也可以

JENKINS_PORT="PORT"

  • 启动jenkins并设置为开机自启动
systemctl start jenkins
systemctl enable jenkins

2.2.3 创建凭证

创建向gitlab拉取代码时的凭证

1646188588490.png

可以选择用户名密码,就是gitlab的用户名密码,需要用户有对项目管理的权限,填写的描述是在选择认证方式时的提示

2.2.4 创建任务

  • 点击新建任务,创建一个任务
1646188951167.png
1646189008169.png

新建任务一般是自由风格(freestyle)、maven、流水线(pipeline)较多,每种类型的构建其实都可以完成一样的构建过程与结果,只是在操作方式、灵活度等方面有所区别,在实际开发中可以根据自己的需求和习惯来选择(流水线类型灵活度较高)

点击新创建的项目

1646189183179.png

点击配置,源码管理选择Git

1646189652044.png

填写git代码url,选择相应认证方式;http选择用户名密码认证,ssh选择密钥认证;选择分支

选择构建方式

1646190125783.png

点击立即构建

1646189833246.png

点击控制台输出,查看构建日志

1646189922207.png

2.2.5 免密登陆

  • 在任意一台服务器生成密钥对
ssh-keygen -t rsa

在/root/.ssh目录下,找到公私钥对,.pub结尾的是公钥

  • 在gitlab配置公钥
1646190494474.png

点击SSH Keys,填写公钥,点击Add key

1646190873978.png
  • 在jenkins添加私钥
1646191159269.png

在添加凭据的位置,类型选择SSH Username with private key,填写的描述是选择凭据时的提示,用户名是生成公私钥的用户,点击Add,将私钥粘贴进去

2.2.6 配置mvn

  • 在系统配置,全局配置中配置环境变量
1646191651546.png
1646191730308.png

添加这几个环境变量;注意添加主机PATH环境变量,不然在编译的时候会报错不能执行命令;"PATH+EXTRA"是固定名字

2.2.7 pipeline

pipeline是一套运行在jenkins上的工作流框架,将原来独立运行与单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作

pipeline优点:

代码:pipeline以代码的形式实现,通常被检入源代码控制,使团队能够编辑,审查和迭代其传送流程

持久:无论是计划内的还是计划外的服务器重启,pipeline都是可恢复的

可停止:pipeline可接收交互式输入,以确定是否继续执行pipeline

多功能:pipeline支持实现世界中复杂的持续交付要求,支持fork/join、循环执行,并行执行任务的功能

可扩展:pipeline插件支持其DSL的自定义扩展,以及与其他插件集成的多个选项

特点:

pipeline脚本是由Groovy语言实现的,支持两种语法,Declaration(声明式)和Scripted Pipeline(脚本式)语法

pipeline有两种创建方法:可在jenkins的Web UI界面中输入脚本,也可以通过一个jenkinsfile脚本文件放入项目源码库中(推荐在jenkins中直接从源代码控制(SCM)中直接载入jenkinsfile pipeline的方法)

2.3 镜像升级与回滚

2.3.1 deployment控制器

deployment控制器支持两种更新策略,默认为滚动更新

  • 滚动更新

滚动更新(rollingUpdate)是默认的更新策略,基于新版本镜像创建新版本pod,然后删除一部分旧版本pod,然后再创建新版本pod,再删除一部分旧版本pod,知道旧版本pod删除完成;滚动更新优势在于升级过程中不会导致服务不可用,缺点是升级过程中会导致两个版本在短时间内并存

升级过程是在执行更新操作后k8s会再创建一个新版本的ReplicaSet控制器,在删除旧版本的ReplicaSet控制器下的pod时,也会在新版本的ReplicaSet控制器下创建新的pod,知道旧版本的pod更新完,再把旧版本的ReplicaSet控制器也回收

在执行滚动更新的同时,为了保证服务的可用性(pod拉取镜像进行创建并且执行探针探测期间是不可用的),当前控制器内不可用的pod不能超出一定范围,需要保留一定数量的pod以保证服务可以被客户端正常访问

pod可用比例可以通过命令设置

kubectl explain deployment.spec.strategy

deployment.spec.strategy.rollingUpdate.maxSurge:指定在升级期间pod总数可以超出期望的pod数量或者百分比,默认为25%,如果设置10%,就是当前有100个pod,那么升级时最多可以共存110个pod,也就是额外有10%的pod临时超出ReplicaSet指定的副本数

deployment.spec.strategy.rollingUpdate.maxUnavailable:指定在升级期间最大不可用的pod数量,可以是数值或者百分比,默认是25%,就是当前有100个pod,那么升级时最多可以有25个(25%)pod不可用,即还有75个(75%)pod是可用的

注意:以上两个值不能同时为0,如果maxUnavailable最大不可用pod为0,maxSurage超出pod数也为0,那么将会导致pod无法进行滚动更新

  • 重建更新

重建(recreate)更新是先删除现有的pod,然后基于新版本的镜像重建,优势是同时只有一个版本提供服务,不会产生多版本在线问题,缺点是pod删除后到pod重建成功之间的时间,服务无法访问,因此使用较少

  • 版本升级

更新镜像

kubectl -n NAMESPACE set image deployment/DEPLOYMENT CONTAINER_NAME=IMAGE:VERSION --record=true

--record=true可以记录变更命令,在查看历史信息命令的CHANGE-CAUSE里显示

查看历史信息

kubectl -n NAMESPACE rollout history deployment DEPLOYMENT

rollout有效资源种类包括:deployments、daemonsets、statefulsets

回滚版本

kubectl -n NAMESPACE rollout undo deployment DEPLOYMENT

回滚到上一个版本;再次执行命令的时候,是回滚到当前版本

比如deployment现在三个版本,nging的1.19、1.20、1.21;当前版本是nginx:1.21,上一个版本是nginx:1.20,执行回滚命令会回滚到nginx:1.20,现在对于更新后的版本来说,nginx:1.20是当前版本,上一个版本是nginx:1.21,所以再次执行回滚命令是回滚到nginx:1.21,而不会回滚到nginx:1.19

每次执行回滚命令,当前版本号为现有最大版本号(REVISION)加一,也就是最新版本号

回滚到指定版本

kubectl -n NAMESPACE rollout undo deployment DEPLOYMENT --to-revision=1

回滚到版本号为1的版本,现有最新版本号加1,成为最新的版本(回滚指定的历史版本号会消失,变成最新版本号)

2.3.2 自动化

gitlab,jenkins,和set images命令,可以实现业务的自动化更新功能(结合shell脚本),如果需要业务回滚,可以使用rollout undo命令

三、亲和与污点

3.1 pod创建流程

  1. 用户通过kubectl命令行或者dashboard创建pod请求,发给kube-apiserver,kube-apiserver负责鉴权和准入,然后把请求写入etcd
  2. 一直监听kube-apiserver的kube-scheduler按照策略进行调度(nodeSelector、nodeAffinity等),如果没有声明策略,会执行默认策略
  3. kube-scheduler给pod选定node,第一步先过滤掉不符合条件的node(例如node资源不足,不符合pod需求),第二步在可用的多个节点之间进行打分,选择其中得分最高的节点进行绑定
  4. kube-scheduler将绑定关系返回给kube-apiserver,由kube-apiserver再把数据写入etcd
  5. node节点上一直监听kube-apiserver的kubelet,如果发现有本机需要创建pod的事件,kubelet会将事件获取过来,然后在本机调用容器运行时,创建pod

3.2 nodeSelector

基于标签选择器,将pod调度到目的节点上

  • 打标签
kubectl label node NODE_IP KEY=VALUE
  • 删除标签
kubectl label node NODE_IP KEY-

删除标签是key后边加上减号

  • depolyment的yaml文件中声明nodeSelector选择器
      nodeSelector:
        KEY: VALUE

层级:deployment.spec.template.spec.nodeSelector

如果有多个标签时,必须同时满足,不然pod调度不成功

3.3 nodeName

选定node名字创建pod

  • depolyment的yaml文件中声明nodeName选择器
    spec:
      nodeName: 192.168.204.102

层级:deploy.spec.template.spec.nodeName

使用较少

3.4 nodeaAffinity

3.4.1 nodeaAffinity简介

affinity是kubernetes 1.2版本后引入的新特性,类似于nodeSelector,允许使用者指定一些pod在Node间调度的约束,目前支持两种形式:

  • requiredDuringSchedulingIgnoredDuringExecution

必须满足pod调度匹配条件,如果不满足则不进行调度

  • preferredDuringSchedulingIgnoredDuringExecution

倾向满足pod调度匹配条件,不满足的情况下会调度到不符合条件的node上

IgnoredDuringExecution表示如果在pod运行期间node的标签发生变化,导致亲和性策略不能满足,也会继续运行当前pod

  • 操作符支持And、In、NotIn、Exists、DoesNotExist、Gt、Lt
  • 可以设置软匹配和硬匹配,在软匹配下,如果调度器无法匹配节点,仍然将pod调度调度到其他不符合条件的节点
  • 可以对pod定义亲和性策略,例如,允许一些pod可以或者不可以调度到同一台node

In:标签的值存在匹配列表中(匹配成功就调度到目的node,实现node亲和)

NotIn:标签的值不存在指定的匹配列表中(不会调度到目的node,实现反亲和)

Gt:标签的值大于某个值(字符串)

Lt:标签的值小于某个值(字符串)

Exists:指定的标签存在

注:如果定义一个nodeSelectorTerms(条件)中通过一个matchExpressions(匹配表达式)基于列表指定了多个条件,则只要满足其中一个条件,就会被调度到相应的节点上。

   如果定义一个nodeSelectorTerms中都通过一个matchExpressions(匹配表达式)指定key匹配多个条件,则所有的条件都必须满足才会调度到相应节点,即and关系。

3.4.2 亲和性硬策略

requiredDuringSchedulingIgnoredDuringExecution即硬策略

  • depolyment的yaml文件中声明Affinity选择器硬策略,多个matchExpressions
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1,多个values可以调度
              - key: KEY1
                operator: In
                values:
                - VALUE1 # 只有一个value匹配成功也可以调度
                - VALUE2
            - matchExpressions: #匹配条件2,多个matchExpressions,任意一个matchExpressions的values中有一个value匹配成功就可以调度
              - key: KEY2
                operator: In
                values:
                - VALUE3  #即使这两个条件都匹配不上也可以调度
                - VALUE4

层级:deployment.spec.template.spec.affinity

多个matchExpressions,任意一个标签的任意一个值匹配成功就可以

  • depolyment的yaml文件中声明Affinity选择器硬策略,多个key
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1
              - key: KEY1
                operator: In
                values:
                - VALUE1
                - VALUE2 #同个key的多个value只有有一个匹配成功就行
              - key: KEY2 #条件1和条件2必须同时满足,否则不调度
                operator: In
                values:
                - VALUE3

层级:deployment.spec.template.spec.affinity

多个key,都满足条件才可以

如果调度失败会报错:

Warning FailedScheduling 45s default-scheduler 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector

3.4.3 亲和性软策略

preferredDuringSchedulingIgnoredDuringExecution即软策略

  • depolyment的yaml文件中声明Affinity选择器软策略
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: KEY1
                operator: In
                values:
                  - VALUE1
          - weight: 60
            preference:
              matchExpressions:
              - key: KEY2
                operator: In
                values:
                  - VALUE2

层级:deployment.spec.template.spec.affinity

软策略中可以设置weight(权重),优先匹配权重高的key

软策略即使所有的key匹配都不成功,也会可以成功调度到node上

3.4.4 亲和性结合使用

硬策略和软策略结合使用

  • depolyment的yaml文件中声明Affinity选择器硬策略和软策略结合使用
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: #硬限制
            nodeSelectorTerms:
            - matchExpressions: #硬匹配条件1
              - key: "kubernetes.io/role"
                operator: NotIn
                values:
                - "master" #硬性匹配key 的值kubernetes.io/role不包含master的节点,即绝对不会调度到master节点(node反亲和)
          preferredDuringSchedulingIgnoredDuringExecution: #软限制
          - weight: 80
            preference:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - magedu
          - weight: 100
            preference:
              matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd

层级:deployment.spec.template.spec.affinity

首先匹配硬策略,然后根据权重匹配软策略

3.4.5 反亲和性

operator为NotIn,即为反亲和性

  • depolyment的yaml文件中声明Affinity选择器反亲和性
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1
              - key: disktype
                operator: NotIn
                values:
                - hdd #绝对不会调度到hdd的节点

层级:deployment.spec.template.spec.affinity

不会调度到NotIn声明的键值对的node上

3.5 podAffinity

3.5.1 podAffinity简介

pod亲和性与反亲和性可以基于已经在节点上运行的pod标签,约束新创建的pod调度的目的节点,注意不是node标签,是pod的标签;pod亲和性与反亲和性可以通过LabelSelector选择namespace,是应为pod是命名空间限定的,而node不属于任何namespace

目前支持两种形式:

  • requiredDuringSchedulingIgnoredDuringExecution

硬策略

  • preferredDuringSchedulingIgnoredDuringExecution

软策略

Pod亲和性与反亲和性操作符:In、NotIn、Exists、DoesNotExists

对于pod亲和性和反亲和性而言,硬策略和软策略中的topoloygKey不允许为空

对于硬策略要求的pod反亲和性,准入控制器LimitPodHardAntiAffinityTopology被引入以确保topologyKey只能是kubernetes.io/hostname;如果希望topologyKey可以用于其他定制拓扑逻辑,可以更改准入控制器或者禁用。

3.5.2 亲和性软策略

  • depolyment的yaml文件中声明Affinity选择器软策略pod亲和性
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: KEY
                  operator: In
                  values:
                    - VALUE
              topologyKey: kubernetes.io/hostname
              namespaces:
                - linux

层级:deployment.spec.template.spec.affinity

匹配键为KEY,值为VALUE的pod标签,优先调度到匹配成功的pod所在的节点上

3.5.3 亲和性硬策略

  • depolyment的yaml文件中声明Affinity选择器硬策略pod亲和性
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: KEY
                operator: In
                values:
                  - VALUE
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - linux

层级:deployment.spec.template.spec.affinity

匹配键为KEY,值为VALUE的pod标签,必须调度到匹配成功的pod所在的节点上

3.5.4 反亲和硬策略

  • depolyment的yaml文件中声明Affinity选择器硬策略pod反亲和性
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: KEY
                operator: In
                values:
                  - VALUE
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - linux

层级:deployment.spec.template.spec.affinity

关键字为podAntiAffinity,node亲和没有这个选项

键为KEY,值为VALUE的pod标签,不会调度到匹配成功的pod所在的节点上

3.5.5 反亲和软策略

  • depolyment的yaml文件中声明Affinity选择器软策略pod反亲和性
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: LINUX
                  operator: In
                  values:
                    - VALUE
              topologyKey: kubernetes.io/hostname
              namespaces:
                - linux

层级:deployment.spec.template.spec.affinity

键为KEY,值为VALUE的pod标签,优先不调度到匹配成功的pod所在的节点上

3.6 Taints和Tolerations

3.6.1 taints简介

  1. 污点(taints)用于node节点排斥pod调度,与亲和和作用是完全相反的,即taint的node和pod是排斥调度关系
  2. 容忍(toleration)用于pod容忍node节点的污点信息,即node有污点信息也会将新的pod调度到该node

https://kubernetes.io/zh/docs/concepts/scheduling-eviction/taint-and-toleration/

3.6.2 污点设置与取消

  • 给nodes设置污点
kubectl taint node NODE_IP key1=value1:NoSchedule

污点类型:

NoSchedule:表示k8s不会把pod调度到具有污点的node上

PreferNoSchedule:表示k8s优先不调度到具有污点的node上

NoExecute:表示k8s不会把pod调度到具有污点的node上,同时会把node上已经存在的pod强制驱逐出去

  • 取消污点
kubectl taint node NODE_IP key1:NoSchedule-

3.6.3 tolerations简介

  1. tolerations(容忍)定义pod的容忍度,可以调度至含有污点的node。
  2. 容忍基于operator的匹配污点

operator有两种

Exists:容忍度不需要value二十直接匹配污点类型

Equal:需要指定value并且value值等于tolerations的key

3.6.4 容忍设置

  • 设置容忍
      tolerations:
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoSchedule"

层级:deployment.spec.template.spec.tolerations

匹配key、value、effect的值,匹配成功,可以容忍污点(优先调度到没有污点的节点)

3.6 驱逐

3.6.1 驱逐简介

驱逐(eviction,节点驱逐),用于当node节点资源不足的时候自动将pod进行强制驱逐,以保证当期node节点的正常运行。k8s基于QoS(服务质量等级)驱逐pod,QoS等级包括:

  1. Guaranteed:limits和requests相等(最后驱逐)
  2. Burstable:limits高于requests(次之)
  3. BestEffort:没有限制,即resources为空(最先驱逐)

当宿主机资源不足时,pod还在向宿主机申请资源,宿主机内核为了保证正常运行,会把占用资源较多的进程杀掉,以保证主机能正常运行,杀掉进程之后,就会触发驱逐(pod状态eviction),pod挂了之后,kube-controller-manager会在别的主机重建

kubelet有默认值,即使没配置,也会驱逐;如果resources配置不合理,pod有可能会被反复驱逐

  • kube-controller-manager实现eviction:node宕机后驱逐
  • kubelet实现eviction:基于node负载、资源利用率等

3.6.2 驱逐条件

  • 软驱逐

软驱逐不会立即驱逐pod,可以自定义宽限期,在条件持续到宽限期限还没有恢复,kubelet再强制杀死pod并触发驱逐

eviction-signal:kubelet捕获node节点信号,进行判断是否驱逐,比如通过cgoupfs获取memory.available的值

operator:基于预算符比对条件是否匹配资源使用情况

quantity:获取node节点资源使用率进行驱逐,可以使用百分比或者单位指定,如内存1Gi等

eviction-soft:软驱逐条件,如memory.available<1.5Gi,如果驱逐条件持续时长超过指定的宽限期,会触发pod驱逐

eviction-soft-grace-period:驱逐宽限期,如memory.available=1m30s,定义软驱逐条件在触发pod驱逐之前时长

eviction-max-pod-grace-period:在满足软驱逐条件而终止pod时的最大允许宽限期(以秒为单位)

  • 硬驱逐

硬驱逐条件没有宽限期,当达到硬驱逐条件时,kubelet会强制立即杀死pod并驱逐

kubelet具有以下默认硬驱逐条件(可以自行跳转):

imagefs.available<15%
memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%

查看kubelet配置中硬驱逐配置:

cat /etc/systemd/system/kubelet.service
cat /var/lib/kubelet/config.yaml

配置如下:

eventBurst: 10
eventRecordQPS: 5
evictionHard:
imagefs.available: 15%
memory.available: 300Mi
nodefs.available: 10%
nodefs.inodesFree: 5%(宿主机节点)

四、Prometheus

4.1 监控简介

监控的重要性:通过业务监控系统,全面掌握业务环境的运行状态,通过白盒监控能够提前预知业务瓶颈,通过黑盒监控能够第一时间发现业务故障并通过告警通告运维人员进行紧急恢复,从而将业务影响降到最低。

黑盒监控:关注实时的状态,一般都是正在发生的事件,比如nginx web界面打开报错503等,即黑盒监控重点在于能对正在发生的故障进行通知告警

白盒监控:关注的是原因,也就是系统内部暴露的一些指标数据,比如nginx后端服务器响应时间长等

监控系统需要能够有效的支持白盒监控和黑盒监控,通过白盒监控能够了解内部的运行状态,以及对监控指标的观察,能够预判可能出现的潜在问题,从而对潜在的不确定因素进行提前优化并避免问题的发生;通过黑盒监控(如HTTP探针、TCP探针)可以在系统或服务发生故障时快速通知相关人员进行处理

通过完善的监控体系,达到以下目的:

长期趋势分析:通过对监控样本数据的持续收集和统计,对监控指标进行长期趋势分析。例如,通过对磁盘空间增长率的判断,我们可以提前预测在未来什么时间点需要对资源进行扩容

对照分析:两个版本的系统运行资源使用情况的差异性,在不同容量情况下系统的并发和负载对比

告警:当系统出现或者即将出现故障时,监控系统迅速通知管理员,从而针对告警内容进行快速的处理

故障分析与定位:当问题发生后,需要对问题进行调查和处理;通过对监控和历史数据的分析,找到并解决根源问题

数据可视化:通过可视化仪表盘能够直接获取系统的运行状态、资源使用情况、以及服务运行状态等直观的信息

4.2 常用监控软件

开源软件监控:cacti、nagios、zabbix、smokeping、open-falcon、nightingale、prometheus等

  • Cacti

https://www.cacti.net/

https://github.com/Cacti/cacti

cacti是基于LAMP平台展现的网络流量监测及分析工具,通过SNMP技术或自定义脚本从目标设备、主机获取监控指标信息;其次进行数据存储,调用模板将数据存到数据库,使用rrdtool存储和更新数据,通过rrdtool绘制结果图形;最后进行数据展现,通过web方式将监控结果呈现出来,常用于在数据中心监控网络设备。

  • Nagios

https://www.nagios.org/

Nagios是用来监视系统和网络的开源应用软件,利用其众多的插件实现对本机和远端服务的监控,当被监控对象发生异常时,会及时向管理员告警,提供一批预设好的监控插件,用户可以调用,也可以自定义shell脚本来监控服务,适合各企业的业务监控,可通过web页面显示监控对象状态、日志、告警信息,分层告警机制及自定义监控相对薄弱。

  • SmokePing

https://www.oetiker.ch/home/oss-2/projekte/smokeping/

Somkeping是一款用于网络性能检测的开源监控软件,主要用于对IDC的网络状况、网络质量、稳定性等做检测,通过rrdtool制图,展示网络的时延情况。

  • open-falcon

http://open-falcon.org/

https://github.com/XiaoMi/open-falcon

小米公司开源的监控软件,open-falcon(猎鹰),监控能力和性能较强

  • Nightingale

https://n9e.didiyun.com/

https://n9e.gitee.io/

夜莺( Nightingale )是一款经过大规模生产环境验证的、分布式高性能的运维监控系统,由滴滴基于open-falcon二次开发后开源出来的分布式监控系统

  • Zabbix

https://www.zabbix.com/

目前使用较多的开源监控软件,可横向扩展,自定义监控项,支持多种监控方式,可监控网络与服务等

zabbix 6.0支持监控kubernetes(centos系统只有8以上支持)

  • prometheus

https://prometheus.io/

https://github.com/prometheus/prometheus

针对容器环境的开源监控软件

商业监控解决方案

  • 监控宝

https://www.jiankongbao.com/

  • 听云

https://www.tingyun.com/

4.3 Prometheus简介

prometheus是基于go语言开发的一套开源的监控、报警和时间序列数据库的组合,是有SoundCloud公司开发的开源监控系统,prometheus于2016年加入CNCF(Cloud Native Computing Foundation,云原生计算基金会),于2018年8月9日成为继kubernetes之后毕业的第二个项目,prometheus在容器和微服务领域得到了广泛的应用。

特点如下:

使用key-value的多维度(多个角度、层面)格式保存数据

使用时序数据库

支持第三方Dashboard实现更好的图形界面,如grafana(grafana 2.5.0版本及以上)

组件模块化

不需要依赖存储,数据可以本地保存,也可以远程保存

平均每个采样点仅占3.5bytes,且一个Prometheus Server可以处理数百万级别的metrics指标数据

支持服务自动化发现(基于consul等方式动态发现被监控的目标服务)

强大的数据查询语句(PoemQL,Prometheus Query Language)

数据可以直接进行算术运算

易于横向伸缩

众多官方和第三方的exporter实现不通的指标数据收集

容器监控的实现方式对比虚拟机或物理机来说,有较大的区别,比如容器在k8s环境中可以任意横向扩容与缩容,那么就需要监控服务能够自动对新创建的容器进行监控,当容器删除后,有能够及时的从监控服务总删除,而传统的zabbix的监控方式需要在每个容器中安装启动agent,并且在容器自动发现注册及模板关联方面并没有比较好的实现方式。

Prometheus包含以下组件:

prometheus server:主服务,接受外部http请求,收集、存储与查询数据等

prometheus targets:静态收集的目标服务数据

service discovery:动态发现服务

prometheus alerting:报警通知

push gateway:数据收集代理服务器(类似于zabbix proxy)

data visualization and exporter:数据可视化与数据导出(访问客户端)

4.4 安装

4.4.1 docker安装

下载地址

docker run -p 9090:9090 prom/prometheus

官方示例需要指定配置文件挂载路径,也可以不挂载,直接跑起来

4.4.2 operator安装

github上对比k8s版本,找到合适的版本,这里以k8s v1.22.2为例,operator版本为0.9

git clone -b release-0.9 https://github.com/prometheus-operator/kube-prometheus.git
  • 首先到kube-prometheus/manifests/setup目录下执行
kubectl apply -f .
  • 然后后退一层目录,到kube-prometheus/manifests目录下执行
 kubectl apply -f .

下载后需要修改k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.1.1和k8s.gcr.io/prometheus-adapter/prometheus-adapter:v0.9.0的镜像,这google官方的仓库,访问不了,可以去docker官方镜像仓库找到替换下

  • 修改prometheus-service.yaml文件,端口类型改成NodePort类型,重新执行
kubectl apply -f prometheus-service.yaml
  • 修改grafana-service.yaml文件,端口类型改成NodePort类型,重新执行
kubectl apply -f grafana-service.yaml

你可能感兴趣的:(k8s伸缩与亲和)