容器编排-K8S

2021/03/30

参考资料

  • Kubernetes文档
  • Kubernetes技术栈 Kubernetes学习指南:https://www.k8stech.net/k8s-book/
  • Kubernetes技术栈:https://www.k8stech.net/
  • 云原生资料库:https://lib.jimmysong.io/
  • [云原生资料库 kubernetes基础教程](https://lib.jimmysong.io/kubernetes-handbook/)
  • [kubernetes-handbook Kubernetes 中文指南/云原生应用架构实战手册](https://jimmysong.io/kubernetes-handbook/)
    • https://github.com/rootsongjc/kubernetes-handbook
    • pdf下载:https://github.com/rootsongjc/kubernetes-handbook/releases
  • [云原生资料库 迁移到云原生应用架构](https://jimmysong.io/migrating-to-cloud-native-application-architectures/chapter1/why-cloud-native-application-architectures.html)
  • Ingress的概念和原理
  • Ingress详细介绍
  • K8s ❉ 基本数据存储详解-EmptyDir/HostPath/NFS:https://blog.csdn.net/wangjie72270/article/details/122298692
  • Kubernetes 学习笔记 https://blog.csdn.net/soosky/article/details/129689710#t86
  • istio-handbook
  • 慕课教程-第29周 容器编排-K8S

一、K8S介绍

Kubernetes 是 Google 基于 Borg 开源的容器编排调度引擎,作为 CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的目标不仅仅是一个编排系统,而是提供一个规范,可以让你来描述集群的架构,定义服务的最终状态,Kubernetes 可以帮你将系统自动得达到和维持在这个状态。

更具体的说,Kubernetes 用户可以通过编写一个 YAML 或者 json 格式的配置文件,也可以通过工具 / 代码生成或直接请求 Kubernetes API 创建应用,该配置文件中包含了用户想要应用程序保持的状态,不论整个 Kubernetes 集群中的个别主机发生什么问题,都不会影响应用程序的状态,你还可以通过改变该配置文件或请求 Kubernetes API 来改变应用程序的状态。

  • OCI(Open Container Initiative):开放容器标准,OCI 中定义了两个标准:容器运行时标准和容器镜像标准,实现了这一标准的主流是:runc(也即我们日常说的 Docker)、Kata-Container
  • CRI (Container Runtime Interface):容器运行时接口,CRI中定义了容器和镜像两个接口,实现了这两个接口的目前主流的是:CRI-O、Containerd。(目前 PCI 产品使用的即为 Containerd)。
  • CNI(Container Network Interface):容器网络接口,CNI接口只有两个:容器创建分配网络资源、容器删除释放网络资源。
  • CSI(Container Storage Interface):容器存储接口,用于 Kubernetes 中。

关系
Kubelet 通过轮询 kube-apiserver 来判定是否要在当前节点启动 Pod。
当需要创建 Pod 的时候,Kubelet 会通过调用 CNI 接口获取网络资源(如 IP 等),然后调用 CRI 接口去创建容器,并把网络资源设进容器中。

CRI服务(Containerd、CRI-O)会去调用 OCI 标准运行时(runc、Kata-Container)来创建容器

1.1 K8S整体架构,功能介绍

  • Kubernetes Master : 主节点
    • API Server:请求统一入口
    • kube-Scheduler:节点调度、任务发布
    • Controller Manager:资源统筹管理,资源任务统一调度部署
      • replication controller:复制控制器
      • namespace controller:
    • Etcd:配置集群管理(数据库)
    • Network-Flannel calico canal:通信
    • Node`s Companents
  • Kubernetes Node
    • kubelet: 节点管理,容器的启停管理、分配网络资源…
    • kubelet-proxy(service->endpoint->pod):服务发现、通信
    • docker/containerd:容器,需要真正运行的
    • Pod:运行在一个node上,Kubernetes的最小工作单元,pod中的容器共享网络和存储
      • 一个 Pod 可以有多个容器,在现实场景中,一般一个pod对应一个容器
      • 一个pod对应一个ip(相当于一个逻辑主机),并且这个ip是短暂的,重启后ip会出现变化
    • controller:控制器
      • deployment:部署无状态应用,例如 微服务应用
      • stateSet:部署有状态应用,例如 mysql主从
      • replicaSet
      • daemonSet:
      • job 一次性任务
      • cronjob 定时任务
  • service:是一个抽象概念,它定义了一组服务的多个pod逻辑合集和访问pod的策略
    • 1、能够管理一组pod,为一组具有相同功能的pod提供一个统一的入口地址
    • 2、对组内的pod进行服务发现和负载均衡:endpoint
    • 3、service将请求进行负载分发到后端的各个POD实例上,客户端只需要访问 Service 的 IP,Kubernetes 则负责建立和维护 Service 与 Pod 的映射关系

二、K8S基础集群搭建-3节点

  • 使用 kubeadm 创建 K8S 集群
  • 使用 kind 创建 K8S 集群
  • 使用 Kubespray 创建 K8S 集群

CentOS 上部署 Kubernetes 集群

软件安装-docker、kubelet、kubeadm、kubectl
master上创建集群-kubeadm init & kubeadm apply
node加入集群-kubeadm join

三、K8S原理剖析与实战

5 【原理剖析】K8S调度原理剖析与Pod生命周期管理

6 【原理剖析】K8S控制器管理原理剖析与实战

7 【原理剖析】Yaml配置实战总结

8 【原理剖析】K8S网络模型原理剖析与实战

9 【原理剖析】K8S服务发现与负载均衡原理剖析与实战

10 【架构思考】K8S系统分层架构回顾和故障排除思路

11 【原理剖析】K8S存储原理剖析与实战

12 【原理实战】K8S存储原理实战-1

13 【原理实战】K8S存储原理实战-2

14 【原理剖析】K8S认证授权原理剖析与实战

15 【架构思考】如何实现集群访问的安全性、可用性、完整性

16 【核心基本功】K8S管理界面日常操作

17 【知识扩展】K8S集群监控,实现快速故障排查和业务连续性保障

18 【性能监控Demo】prometheus时间序列监控,知其然

19 【日志监控Demo】ELK日志管理,知其所以然

20 【架构思考】如何实现大规模集群?10节点-100节点-1000节点

21 【架构升级】全链路高可用架构升级

22 【知识扩展】如何基于容器编排工具实现CICD

23 【K8S技术落地实战】部署微服务-1

24 【K8S技术落地实战】部署微服务-2

25 【K8S技术落地实战】部署微服务-3

26 【K8S技术落地实战】部署微服务-4

27 【K8S技术落地实战】部署微服务-5

四、kubectl常用命令

## 查看集群信息
kubectl cluster-info

## 查看node信息
kubectl get nodes -o wide

## 查看pod信息
kubectl get pods -A -o wide -n namespace

## 创建 查看namespace
kubectl create namespace abc
kubectl get ns

## 发布删除应用
kubectl apply -f appserver.yaml
kubectl delete -f appserver.yaml

## 查看服务service
kubectl get svc -n namespace1

## 查看ingress
kubectl get ingress -A
kubectl describe ing, svc -n namespace 

## 查看日志
# 输出一个单容器pod POD的日志到标准输出
$ kubectl logs podName

# 持续输出一个单容器pod POD的日志到标准输出
kubectl logs --tail=200 -n default demo-server -f
kubectl logs -f --tail=200 pods/appServer-0 -n default
kubectl logs -f --tail=200 pods/appServer-0 -n default|grep 'time out' 

## 查看服务重启前一版本的日志输出
kubectl logs -f --tail 100 XXXpod -n namespace --previous
 
## 进入pod
kubectl exec -it -n ingress-nginx /bin/bash 

## 查看pod启动失败报错
kubectl describe pod demo-server-645bf9cfbd-ngkr4 -n default

## copy容器内日志文件
kubectl cp default/appServer-0:/opt/1.log /home/1.log

## 动态日志导出
kubectl logs appServer-0 -n default | grep '2022-10-31 17:*' > /tmp/appServer-0.txt

## 导出yaml
kubectl get pods appServer-deployment-0 -n default -o yaml
kubectl get deployment appServer-deployment -n default -o yaml > ./appServer-deployment.yaml
kubectl get service appServer-service -n default -o yaml > ./appServer-service.yaml

## 创建证书
kubectl get secrets -n demo
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=wds.demo.com"
kubectl create secret tls tls-secret --key tls.key --cert tls.crt -n demo

##查看node内存使用
kubectl top node -n namespace1 --sort-by memory  

## 查看pod内存使用
kubectl top po -n namespace1 --sort-by memory 

# 容器创建阻塞,不知道yaml在哪里
kubectl get deployment -n grafana  # 查看副本状态
kubectl scale deployment  grafana --replicas=0 -n grafana  #副本缩为0
kubectl scale deployment  grafana --replicas=1 -n grafana  #副本扩为1

# 扩缩容器副本数
$ kubectl scale deployment DEPLOYMENT --replicas=8
$ kubectl scale statefulset loki --replicas=1 -n loki

# 显示pod节点的标签信息
$ kubectl get pod --show-labels

# 根据指定标签匹配到具体的pod
$ kubectl get pod -l app=example(标签键值对)

# 查看最近几秒,几分,或者几小时,几天的日志信息,--since 选参 
$ kubectl  logs -f -n namespace pod-name --since=1h

# 指定时间戳输出日志
$ kubectl logs podName --since-time=2018-11-01T15:00:00Z
指定某个时间点之后的日志信息查看,--since-time 选参
表示查看12月22号10点之后的日志信息 +00:00 表示这个时间点向前推多长时间的日志
$ kubectl logs -f -n namespace pod-name --since-time="2021-12-22T02:00:00+00:00"

# 查看运行pod的环境变量
$ kubectl exec podName env

## k3s节点证书过期
### k3s证书过期时间检查:
### k3s server:
for i in `ls /var/lib/rancher/k3s/server/tls/*.crt`; do echo $i; openssl x509 -enddate -noout -in $i; done
### 重启k3s更新证书:
systemctl restart k3s
### k3s agent:
for i in `ls /var/lib/rancher/k3s/agent/*.crt`; do echo $i; openssl x509 -enddate -noout -in $i; done
### 重启k3s agent更新证书:
systemctl restart k3s-agent 

#将pod调度到特定节点的几种方式
https://blog.csdn.net/ApexPredator/article/details/130895114

## 在K3s中,您可以使用kubectl命令行工具给节点打上标签

给名为node-name的节点添加一个名为key=value的标签。
kubectl label nodes node-name key=value

如果您想要更新或覆盖现有的标签,可以添加--overwrite标志。
kubectl label nodes node-name key=value --overwrite

如果您想要查看节点的标签,可以使用以下命令:
kubectl get nodes --show-labels

或者针对特定节点查看标签:
kubectl describe node node-name

五、yml配置总结

apiVersion: batch/v1
kind: Job
metadata:
  name: demo-job
  namespace: demo-ns
spec:
  template:
    metadata:
      name: demo-job
    spec:
      nodeName: 192.168.1.1  //指定pod运行node
      hostAliases:  //配置pod的hosts域名解析
        - hostnames:
            - "h1.tdengine.com"
          ip: 192.168.1.1
        - hostnames:
            - "h2.tdengine.com"
          ip: 192.168.1.2
        - hostnames:
            - "h3.tdengine.com"
          ip: 192.168.1.3
      containers:
      - name: demo-job
        image: demo-job:1.15.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3100
          name: http
          protocol: TCP
      - env: 
        resources: //资源限制
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: 200m
            memory: 256Mi    

六、k8s-namespace下项目TLS证书创建、配置、更新

## 1.证书创建或购买  
上传创建或购买的证书xx.key xx.pem

## 2.创建命名空间下的secret 
kubectl create secret tls sre-secret --namespace grafana --key xx.key --cert xx.pem
查看 
kubectl get secrets -n grafana
kubectl get secrets -n grafana sre-secret -o yaml

## 3.编辑业务grafana-ingress.yml,配置域名证书
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grafana
  namespace: grafana
  labels:
    app.kubernetes.io/name: grafana
    app.kubernetes.io/instance: grafana
spec:
  ingressClassName: nginx
  tls:
    - hosts:
      - grafana.xx.cn
      secretName: sre-secret
  rules:
    - host: grafana.xx.cn
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: grafana
                port:
                  number: 80

## 4.证书过期更新  
上传新的证书xx.key xx.pem  
kubectl delete secrets -n grafana sre-secret
kubectl create secret tls sre-secret --namespace grafana  --key xx.key --cert xx.pem

七、k8s集群接入私有镜像仓库

1. 修改hosts指定映射关系(需在k8s 所有工作节点修改)
sudo vim /etc/hosts
192.168.1.1 hub.wds.com

2. containerd 设置为跳过tls认证(需在k8s 所有工作节点修改)
若私有仓库无证书或证书不可靠 需要执行此步骤

sudo vi /etc/containerd/config.toml
      [plugins."io.containerd.grpc.v1.cri".registry.configs]
        [plugins."io.containerd.grpc.v1.cri".registry.configs."hub.wds.com".tls]
          insecure_skip_verify = true
#重启containerd
systemctl daemon-reload
sudo systemctl restart containerd

3. 在业务命名空间创建docker 账号登录的secert
kubectl -n namespace-demo create secret docker-registry demo-regcred \
 --docker-server="http://hub.wds.com" \
 --docker-username="username"  \
 --docker-password='password'

八、k8s集群证书更新

https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/

### 利用kubeadm工具管理证书,手动生成的无法管理(kubeadm配置K8S集群默认ca有效期为10年,其他证书有效期为1年)
### 查看所有证书的状态
kubeadm alpha certs check-expiration

### 更新所有证书
kubeadm alpha certs renew all

### 手动查看证书的到期时间
openssl x509 -in XXX.crt -noout -dates

九、在k8s中将Pod调度到某个节点

1. 通过nodeName直接指定节点

通过在Pod的定义中直接指定nodeName字段,可以强制将Pod调度到指定的节点上。这种方式会绕过调度器的正常调度过程,直接进行绑定。 步骤: • 确定目标节点的名称。 • 通过nodeName字段直接指定节点名称。 • 创建Pod后,Pod将被直接调度到指定的节点上。

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:1.22
        name: nginx
      nodeName: node01
#通过节点名来指定容器部署在哪台节点

2. 通过nodeSelector匹配节点

通过在Pod的定义中指定nodeSelector,可以匹配具有相应标签的节点。 步骤: • 给目标节点添加或确认已有的标签(Label)。 • 通过nodeSelector字段指定要匹配的节点标签。 •创建Pod后,Kubernetes调度器会将Pod调度到匹配该标签的节点上。如果节点不满足条件,pod会进入pending状态。直到节点满足条件为止。

#查看标签
kubectl get nodes --show-labels
#自定义标签:
kubectl label nodes node01 test=c
#删除标签:
kubectl label nodes master1 test-
#复写
kubectl label nodes node02 test=6 --overwrite
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeSelector:
        test: c
      containers:
      - image: nginx:1.22
        name: nginx
#在spec参数设置当中加入nodeSelector字段

3. 使用亲和性(Affinity)和反亲和性(Anti-Affinity)

亲和性和反亲和性提供了更灵活的调度方式,允许根据节点的标签、Pod的标签以及Pod之间的关系来调度Pod。 • 节点亲和性(Node Affinity):允许Pod根据节点的标签来调度。 • Pod亲和性(Pod Affinity):允许Pod根据其他Pod的标签和位置来调度,使得相关的Pod能够调度到相同的节点或同一拓扑域中。 • Pod反亲和性(Pod Anti-Affinity):与Pod亲和性相反,它确保Pod不会被调度到具有相同或特定标签的Pod所在的节点上。

3.1 节点亲和性(Node Affinity)

3.1.1 硬策略

In:

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:1.22
        name: nginx
      affinity:
        #选择亲和性部署的方式
        nodeAffinity:
          #选择的是node节点的亲和性
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            #选择亲和性的策略,你要选择哪个node作为硬策略,匹配的节点的标签
            - matchExpressions:
              #定义一个符合我要选择的node节点的信息
              - key: test
                operator: In
                #指定键值对的算法,指定键值对的算法为 Exists 和 DoesNotExist不能使用values字段
                values:
                - c

NotIn:

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:1.22
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: test
                operator: NotIn
                values:
                - c

Gt(只能比较整数值):

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:1.22
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: test
                operator: Gt
                values:
                - "900"

Lt(只能比较整数值):

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: test
                operator: Lt
                values:
                - "1201"

Exists:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: test
                operator: Exists

DoesNotExist:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: test
                operator: DoesNotExist
3.1.2 软策略

软策略是尽量满足,但不是一定满足。 weight:多个软策略,谁的权重值高(值越大优先级越高),就执行谁。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: memory
                operator: DoesNotExist

3.2 Pod亲和性(Pod Affinity)

3.2.1 硬策略

In:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx1
  name: nginx1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx1
 
  template:
    metadata:
      labels:
        app: nginx1
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: test
#硬策略:表示部署在node节点标签是test,且有pod标签是app、app为nginx的节点

NotIn:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx1
  name: nginx1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx1
         
  template:
    metadata: 
      labels:
        app: nginx1
    spec:    
      containers:
      - image: nginx:1.22.0
        name: nginx 
      affinity:
        podAffinity: 
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions: 
              - key: app
                operator: NotIn
                values:
                - nginx
            topologyKey: test
#硬策略:表示部署在node节点标签是test,且有pod标签是app、app不为nginx的节点

Exists:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
          
  template:
    metadata:
      labels: 
        app: nginx2 
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector: 
              matchExpressions:
              - key: app
                operator: Exists
            topologyKey: test
 
#硬策略:表示部署在node节点标签是test,且有pod标签是app
3.2.2 软策略:

Exists:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx3
  name: nginx3
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx3
 
  template:
    metadata:
      labels:
        app: nginx3
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx3
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: Exists
              topologyKey: test
#软策略:表示部署在node节点标签是test,且pod标签是app

DoesNotExist:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx3
  name: nginx3
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx3
 
  template:
    metadata:
      labels:
        app: nginx3
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx3
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: DoesNotExist
              topologyKey: test
#软策略:表示部署在node节点标签是test,且有pod标签不是app

3.3 Pod反亲和性(Pod Anti-Affinity)

3.3.1 硬策略

In:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
 
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: test
#反亲和性---硬策略In:这里指test节点中含有app=nginx标签不部署服务
#也就是说:除了指定声明的不部署服务,其他的节点部署

NotIn:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
 
  template:
    metadata:
      labels:
        app: nginx2 
    spec: 
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: NotIn
                values:
                - nginx
            topologyKey: test

Exists:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
 
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: Exists
            topologyKey: test
 
 
#反亲和性---硬策略exists:这里指test节点中含有app标签不部署服务
#也就是说:除了此处声明的不部署服务,其他的节点部署

DoesNotExist:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
 
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: DoesNotExist
            topologyKey: test
 
 
#反亲和性---硬策略DoesNotExist:这里指test节点中不含有app标签不部署服务
#也就是说:除了此处声明的不部署服务,其他的节点部署
3.3.2 软策略
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx2
  name: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
 
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - image: nginx:1.22.0
        name: nginx2
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: NotIn
                  values:
                  - nginx
              topologyKey: test
#并非强制,经过预先策略、优先策略后,满足条件就执行并非一定要,只是希望

注意点: pod的亲和性策略。在配置时,必须要加上拓扑域的关键字topologkey指向的是节点标签 pod亲和性的策略也分为硬策略和软策略 pod亲和性的notin可以替代反亲和性 pod亲和性主要是为了把相关联的pod组件部署在同一节点上。例如:LNMP

4. 使用污点(Taints)和容忍度(Tolerations)

节点可以被打上污点,以表明它们具有某些不希望的属性,如特定类型的硬件或软件问题。Pod可以定义容忍度,以表示它们可以容忍节点的污点。这种方式允许管理员将某些Pod限制在特定的节点上,或者防止它们被调度到某些节点上。

4.1 污点

污点:taint是定义在node节点之上的键值型属性数据,用于让node节点拒绝将pod调度运行于其上。 1、污点和容忍可以配合node的亲和性一起使用。 2、污点是node的调用机制,不是pod的 3、被设为污点的节点,不会部署pod 4、污点和亲和性相反,亲和性是尽量选择 和 一定选择 5、污点的节点一定不被选择

污点三种类型: NoSchedule(一定是):k8s不会把pod调度到这个节点上 PreferNoSchedule(希望是但不一定):如果污点类型是它,尽量避免把pod部署在该节点上。(master节点的污点就是这个类型在一定程度上提高资源利用率) NoExecute(驱逐):如果污点类型是它,k8s将会把该节点上的pod驱逐出去,而且也不会调度到这个节点。

#查看污点
kubectl describe nodes 主机名 | grep -i taints
kubectl describe nodes master01 | grep -i taints
 
#设置污点
kubectl taint node 主机名 key=1:NoSchedule
#key=1设置标签的值
#:NoSchedule并将这个值与污点做映射
kubectl taint node node01 key=1:NoSchedule
 
#删除污点
kubectl taint node 主机名 标签:主机污点类型-
kubectl taint node node01 key:NoSchedule-

驱逐的情况: 1、基于控制器创建的pod,虽然被驱逐,会在其他节点重新部署。自主pod会被直接杀死 2、应用场景:节点服务器需要维护,服务器关机,节点上的pod会失效。在工作中,我们主要部署pod的方式控制器部署。deployment最多的。一旦节点设置为驱逐,控制器创建的pod会在其他节点重新部署。 3、所有的pod都会被驱逐,跟命名空间无关,所有的一切都会被驱逐。 4、不论你的创建方式是什么,都会被驱逐 5、系统集群组件(kube-proxy)不会被驱逐

kubectl taint node node02 key=1:NoExecute

4.2 容忍

容忍: 即使节点上设置了污点,有了容忍机制,依然可以在设置为污点的节点上部署pod。 特殊情况: 1、NoExecute依然可以部署pod,但是有生命周期,时间一到,pod会被销毁然后重新拉起。 2、生命周期结束之后,会驱逐一部分pod到其他节点。有的节点还是会保留在污点节点上。 3、节点维护完毕,测试一下节点的挂载是否正常。

4.2.1 NoSchedule
​apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    test: nginx4
  name: nginx4
spec:
  replicas: 6
  selector:
    matchLabels:
      test: nginx4
  template:
    metadata:
      creationTimestamp: null
      labels:
        test: nginx4
    spec:
      containers:
      - image: nginx:1.22
        name: nginx4
      tolerations:
#tolerations:表示容忍
      - key: app
#这里的key是节点的标签名
        operator: Equal
        value: "1"
        effect: NoSchedule
#effect:表示对应的污点类型。必须要和节点的污点保持一致
#表示容忍节点上的标签是key。对应的标签值是1
4.2.2 NoExecute
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    test: nginx2
  name: nginx2
spec:
  replicas: 6
  selector:
    matchLabels:
      test: nginx2
  template:
    metadata:
      creationTimestamp: null
      labels:
        test: nginx2
    spec:
      containers:
      - image: nginx:1.22
        name: nginx2
      tolerations:
      - key: key
        operator: Equal
        value: "1"
        effect: NoExecute
        tolerationSeconds: 36
#effect:表示对应的污点类型。必须要和节点的污点保持一致
#表示容忍节点上的标签是key。对应的标签值是1
#tplerationSeconds:设置节点可以容忍多长时间,单位为秒
4.2.3 不指定key
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      tolerations:
      - operator: Exists
        effect: NoSchedule
#如果没有声明key和value。将会容忍所有污点的key
#key对应节点的污点类型是NoSchedule
#没有key,不匹配节点标签,容忍所有污点,但是类型是指定的类型
4.2.4 不指定类型(effect)
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.22
        name: nginx
      tolerations:
      - key: key
        operator: Exists
#指定节点的标签,但是不指定污点的类型,所有节点上只要包含了这个指定的标签名,可以容忍所有的污点

5. cordon设置节点的调度状态

5.1 cordon:设置不可调度状态

#设置为不可调度状态
kubectl cordon <nodename>
#取消不可调度状态
kubectl uncordon <nodename>

5.2 drain:设置驱逐节点

1、一旦执行drain,被执行的节点会变成不可调度的状态 2、会驱逐该节点上的所有pod

kubectl drain <nodename> --ignore-daemonsets --delete-emptydir-data --force

#drain:开始标记node节点为不可调度,然后驱逐pod
#--ignore-daemonsets:表示忽视,会无视daemonsets部署的pod,他还会在原节点上
#daemonsets一般部署的都是重要的后台系统pod,所以会忽略
#--delete-emptydir-data:有本地挂载卷的pod将会被强制杀死,此选项允许删除这些卷中的数据,旧版本的k8s为--delete-local-data(另外如果跟本身的配置信息有冲突时,drain就不会执行该命令会安全驱逐节点上面所有的pod,安全驱逐的方式将会允许pod 里面的容器遵循指定的 Pod DisruptionBudgets 执行优雅的中止)
#--force:强制释放不是控制器管理的pod
#是控制器创建的将会被驱逐,不是控制器创建的将会被杀死

参考资料

https://developer.aliyun.com/article/1594638 https://blog.csdn.net/qq_61843057/article/details/135458466 https://blog.csdn.net/qq_61843057/article/details/135479458

Post Directory

扫码关注公众号:暂无公众号
发送 290992
即可立即永久解锁本站全部文章