zoukankan      html  css  js  c++  java
  • K8S资源操作

    K8S资源操作

    Namespace

    简介

    名称空间是K8S中的重要一种资源环境,其主要作用提供了容器之间的系统资源隔离以及多租户之间的资源隔离。

    默认情况下所有的pod资源都存储在默认的 default 这个名称空间之中,由于处在同一名称空间因此默认情况下所有的pod可以互相访问,但是实际环境之中可能由于不同的业务运行不同的pod且这些pod互不关联因此我们无需进行容器之间的互相访问,此时就可以将需要关联的容器划分到同一名称空间之中形成逻辑意义上的组,这样方便我们对不同的组资源进行隔离和管理。

    可以通过kubernetes的授权机制,将不同的Namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合K8S的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。

    image-20210927200941163

    应用示例

    # 查看所有名称空间
    [root@master ~]# kubectl get namespaces 
    '''
    default:pod默认存放的名称空间
    kube-node-lease:节点之间进行心跳检测
    kube-public:可以被所有人访问包括未认证的用户
    kube-system:K8S启动所需容器所处资源
    '''
    

    image-20210927202135607

    # 查看指定名称空间
    [root@master ~]# kubectl get namespaces default 
    

    image-20210927202246506

    # 查看名称空间下所拥有的节点
    [root@master ~]# kubectl get pods -n kube-system
    '''
    etcd-master:资源存储
    kube-apiserver-master:指令入口
    kube-scheduler-master:计算节点
    kube-controller-manager-master:节点控制管理
    '''
    

    image-20210927223842344

    # 查看详情
    [root@master ~]# kubectl describe namespaces default 
    '''
    Status:      
      Active:表示名称空间在使用中
      Terminating:标识名称空间在删除中,当名称空间之中容器过多删除过慢处于这个状态
    No resource quota:针对名称空间做限制
    No LimitRange resource:针对名称空间的组件做限制
    '''
    

    image-20210927202954537

    # 指定输出格式为yaml或者json等
    [root@master ~]# kubectl get namespaces default -o yaml/json
    

    image-20210927203245253

    # 创建名为dev的名称空间
    [root@master ~]# kubectl create namespace dev
    
    [root@master ~]# kubectl get namespace
    

    image-20210927203748365

    # 删除名称空间
    [root@master ~]# kubectl delete namespace dev
    
    [root@master ~]# kubectl get namespaces 
    

    image-20210927203941637

    命令式对象配置

    # 创建配置文件
    
    cat > ns-dev.yaml << EOF
    apiVersion: v1
    # 创建种类名称空间
    kind: Namespace
    metadata:
     # 名称空间命名dev
      name: dev
    EOF
    
    # 创建名称空间
    [root@master ~]# kubectl create -f ns-dev.yaml 
    
    [root@master ~]# kubectl get namespaces 
    

    image-20210927204413911

    # 删除名称空间
    [root@master ~]# kubectl delete -f ns-dev.yaml 
    
    [root@master ~]# kubectl get namespaces 
    

    image-20210927204548888

    Pod

    概述

    • Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。

    • Pod可以认为是容器的封装,一个Pod中可以存在一个或多个容器。

    image-20210927210324527

    应用示例

    # 创建并且运行pod
    [root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
    
    '''
    run:pod控制器
    image:容器镜像
    port:暴露端口
    namespace:运行名称空间
    '''
    

    image-20210927231722322

    # 查看详细信息
    [root@master ~]# kubectl describe -n dev pods nginx 
    

    image-20210927235557023

    # 查看IP等信息
    [root@master ~]# kubectl get -n dev pods nginx -o wide
    

    image-20210927235452648

    # 访问容器
    [root@master ~]# curl 10.244.22:80
    

    image-20210927235900582

    # 删除容器[root@master ~]# kubectl delete pod nginx -n dev
    

    image-20210928000408583

    命令式对象配置

    # 创建配置文件
    cat > pod-nginx.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      namespace: dev
    spec:
      containers:
      - image: nginx:1.17.1
        imagePullPolicy: IfNotPresent
        name: pod
        ports: 
        - name: nginx-port
          containerPort: 80
          protocol: TCP
    EOF
    
    # 创建
    [root@master ~]# kubectl create -f pod-nginx.yaml 
    
    [root@master ~]# kubectl get pods nginx -n dev
    

    image-20210928000749338

    # 删除
    [root@master ~]# kubectl delete -f pod-nginx.yaml 
    
    [root@master ~]# kubectl get pods -n dev
    

    image-20210928001053238

    Label

    概述

    • Label是kubernetes的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

    • 可以通过Label实现资源的多纬度分组,以便灵活、方便地进行资源分配、调度、配置和部署等管理工作。

    • label特点

      • 一个label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等。
      • 一个资源对象可以定义任意数量的label,同一个label也可以被添加到任意数量的资源对象上去。
      • label通常在资源对象定义时确定,当然也可以在对象创建后动态的添加或删除
    ● 版本标签:"version":"release","version":"stable"
    ● 环境标签:"environment":"dev","environment":"test","environment":"pro"
    ● 架构标签:"tier":"frontend","tier":"backend"
    

    标签选择器

    • 标签用于对pod进行分类定义,如果需要查找到这些pod就需要标签选择器类似于MySQL中的where条件

      • label用于对pod进行定义标识
      • label selector用于对被标识的pod进行查询和筛选
    • 当前共有两种标签选择器

      • 基于等式的label selector
        • environment=dev:查询键值key=environment并且value=dev的pod
        • environment!=dev:查询键值key=environment并且值value=!dev的pod
      • 基于集合的label selector
        • environment in (dev,test):选择key=environment并且value=dev或者value=test
        • environment not in (dev,test):选择key=environment并且value!=dev或者value!=test
    • 标签选择器可以使用多个,此时多个标签选择器就行组合中间使用逗号分割

      • name=salve,env!=production
      • name not in (master,slave),env!=production

    使用示例

    # 查看pod标签
    [root@master ~]# kubectl get pod nginx -n dev --show-labels 
    

    image-20210928153320610

    # 添加标签 version=1.0
    [root@master ~]# kubectl label pod nginx version=1.0 -n dev
    

    image-20210928153459353

    # 修改标签 --overwrite 覆盖原有标签
    [root@master ~]# kubectl label pod nginx -n dev version=2.0 --overwrite
    

    image-20210928153644271

    # 报错修改需要加上--overwrite
    [root@master ~]# kubectl label pod nginx -n dev version=1.0
    

    image-20210928153732904

    # 删除标签 key-
    [root@master ~]# kubectl label pod nginx -n dev version-
    

    image-20210928153945946

    # 查看所有pod节点
    [root@master ~]# kubectl get pods  -n dev --show-labels 
    

    image-20210928154936586

    # 标签选择器
    [root@master ~]# kubectl get pods -l version=2.0,env=test -n dev --show-labels 
    

    image-20210928155314893

    # 集合选择器
    [root@master ~]# kubectl get pod -l "version in (2.0,1.0)" -n dev --show-labels 
    

    image-20210928155720661

    命令式对象配置

    # 创建文件
    cat > pod-nginx.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      namespace: dev
      labels:
        version: "3.0"
        env: "test"        
    spec:
      containers:
      - image: nginx:1.17.1
        imagePullPolicy: IfNotPresent
        name: pod
        ports: 
        - name: nginx-port
          containerPort: 80
          protocol: TCP
    EOF
    
    # 创建
    [root@master ~]# kubectl create -f pod-nginx.yaml
    
    # 查看
    [root@master ~]# kubectl get pod -n dev --show-labels 
    

    image-20210928160132274

    # 删除
    [root@master ~]# kubectl delete -f pod-nginx.yaml 
    
    [root@master ~]# kubectl get pod -n dev --show-labels 
    

    image-20210928160237786

    Deployment

    概述

    • 在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。

    • Pod控制器用于Pod的管理,确保Pod资源符合预期的状态,当Pod的资源出现故障的时候,会尝试进行重启或重建Pod。

    • 在kubernetes中Pod控制器的种类有很多,本章节只介绍一种:Deployment。

    image-20210928163641913

    应用示例

    # 创建控制器命名为nginx
    [root@master ~]# kubectl create deployment nginx --image=nginx:1.17.1 -n dev
    
    [root@master ~]# kubectl get deployments -n dev
    

    image-20210928164044134

    # 在控制器下创建pod --replicas指定pod数量
    [root@master ~]# kubectl scale deployment nginx -n dev --replicas=4
    
    [root@master ~]# kubectl get pods -n dev
    

    image-20210928164232603

    # 查看deployment详细信息
    [root@master ~]# kubectl describe deployments -n dev
    

    image-20210928164544997

    # 删除控制器下所对应的pod节点
    [root@master ~]# kubectl delete pods -n dev nginx-59975f44cf-kwr7w 
    

    image-20210928164920075

    # 在K8S中控制器会对容器进行监控 当容器出现故障会对容器重新创建
    [root@master ~]# kubectl delete deployments nginx -n dev   # 删除控制器
    [root@master ~]# kubectl get deployments -n dev
    

    image-20210928165443498

    命令式对象配置

    cat > deploy-nginx.yaml << EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      namespace: dev
    spec:
      replicas: 3
      selector:
        matchLabels:
          run: nginx
      template:
        metadata:
          labels:
            run: nginx
        spec:
          containers:
          - image: nginx:1.17.1
            name: nginx
            ports:
            - containerPort: 80
              protocol: TCP
    EOF
    
    # 创建
    [root@master ~]# kubectl create -f deploy-nginx.yaml 
    
    [root@master ~]# kubectl get deployments -n dev
    

    image-20210928165349369

    # 删除
    [root@master ~]# kubectl delete -f deploy-nginx.yaml 
    
    [root@master ~]# kubectl get deployments -n dev
    

    image-20210928165443498

    Service

    概述

    • 上述可以使用控制器来创建一组Pod来提供高可用性的服务且每个Pod都会分配一个单独的Pod的IP地址,但是却存在如下的问题:

      • Pod的IP会随着Pod的重建产生变化。
      • Pod的IP仅仅是集群内部可见的虚拟的IP,外部无法访问

    image-20210928215146533

    • 在K8S中为我们提供了service解决该问题,service可以看做一组pod对外访问的接口,借助service可以实现服务被访问以及负载均衡

    image-20210928215851078

    应用示例

    # 暴露service命名为svc-nginx 使用nginx控制器 -type=ClusterIP给服务暴露ip地址
    [root@master ~]# kubectl expose --name=svc-nginx deployment nginx --type=ClusterIP --port=80 --target-port=80 -n dev
    
    # 查看
    [root@master ~]# kubectl get service -n dev
    

    image-20210928220309677

    # 格式化输出
    [root@master ~]# kubectl get service -n dev -o wide
    

    image-20210928220400152

    # 访问集群 但是此时只允许集群内部访问
    [root@master ~]# curl 10.102.7.34:80
    

    image-20210928220536632

    # --type=NodePort暴露给外部
    [root@master ~]# kubectl expose --name=svc-nginx1 -n dev deployment nginx --type=NodePort --port=8080 --target-port=80
    
    [root@master ~]# kubectl get service -n dev -o wide
    

    image-20210928222541980

    # 集群外部访问
    curl http://10.1.1.2:30719
    

    image-20210928222636751

    # 删除service
    [root@master ~]# kubectl delete service -n dev svc-nginx
    

    image-20210928223020884

    命令式对象配置方式

    cat > svc-nginx.yaml << EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: svc-nginx
      namespace: dev
    spec:
      clusterIP: 10.109.179.231
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: nginx
      type: ClusterIP
    EOF
    
    # 创建
    [root@master ~]# kubectl  create  -f  svc-nginx.yaml
    
    [root@master ~]# kubectl get service -n dev
    

    image-20210928223532624

    # 删除配置
    [root@master ~]# kubectl delete -f svc-nginx.yaml 
    
    [root@master ~]# kubectl get service -n dev
    

    20210928224139746

    Pod配置

    容器属性是pod中非常重要的属性

    [root@master k8s]# kubectl explain pod.spec.containers
    
    '''
    返回的重要属性
    KIND:     Pod
    VERSION:  v1
    RESOURCE: containers <[]Object>   # 数组,代表可以有多个容器FIELDS:
      name  <string>     # 容器名称
      image <string>     # 容器需要的镜像地址
      imagePullPolicy  <string> # 镜像拉取策略本地镜像或者远程仓库镜像
      command  <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
      args   <[]string> # 容器的启动命令需要的参数列表 
      env    <[]Object> # 容器环境变量的配置
      ports  <[]Object>  # 容器需要暴露的端口号列表
      resources <Object> # 资源限制和资源请求的设置
    '''
    

    基本配置

    # 创建yaml文件
    cat > pod.base.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      # pod名称
      name: pod-base
      # 名称空间
      namespace: dev
      # 标签
      labels:
        user: SR
    spec:
      containers:
        # 容器名称
        - name: nginx
          # 镜像
          image: nginx:1.17.1
        - name: busybox
          image: busybox:1.30
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod.base.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get pod -n dev
    

    image-20211007200810889

    # 查看pod详细信息
    [root@master k8s]# kubectl describe -n dev pod pod-base 
    

    image-20211007200955877

    镜像拉取策略

    # 创建pod-imagepullpolicy.yaml
    cat > pod-imagepullpolicy.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-imagepullpolicy
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: Always
        - name: busybox
          image: busybox:1.30
    EOF
    

    K8S镜像拉取策略支持三种

    • Always:一直使用远程仓库拉取镜像
    • IfNotPresent:本地仓库有镜像则使用本地仓库镜像否则就使用远程仓库镜像
    • Never:一直使用本地仓库镜像本地不存在就报错
    '''
    默认值说明
    1.如果tag为具体版本则默认为IfNotPresent
    2.如果tag为最新版本则默认为Never
    '''
    

    创建pod

    [root@master k8s]# kubectl apply -f pod-imagepullpolicy.yaml 
    
    [root@master k8s]# kubectl describe -n dev pod pod-imagepullpolicy 
    

    image-20211007210723988

    启动命令

    在前面的案例中,一直有一个问题没有解决,就是busybox容器一直没有成功运行,那么到底是什么原因导致这个容器的故障的呢?

    在busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。解决方法就是让其一直在运行,这就用到了command的配置。

    cat > pod-command.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-command
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17.1 # 容器需要的镜像地址
          imagePullPolicy: IfNotPresent # 设置镜像拉取策略
        - name: busybox # 容器名称
          image: busybox:1.30 # 容器需要的镜像地址
          command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl apply -f pod-command.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get pod -n dev 
    

    image-20211007213252035

    # 进入pod容器
    [root@master k8s]# kubectl exec -it -n dev pod-command -c busybox /bin/sh
    

    image-20211007213511791

    环境变量

    • 用于给容器配置环境变量
    • 对于环境变量更加推荐在配置文件配置环境变量
    # 创建配置文件
    cat > pod.env.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-env
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17.1 # 容器需要的镜像地址
          imagePullPolicy: IfNotPresent # 设置镜像拉取策略
        - name: busybox # 容器名称
          image: busybox:1.30 # 容器需要的镜像地址
          command:
            [
              "/bin/sh",
              "-c",
              "touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;",
            ]
          env:
            # 设置环境变量的key/value值
            - name: "username"
              value: "SR"
            - name: "password"
              value: "root"
    EOF
    
    [root@master k8s]# kubectl create -f pod-env.yaml 
    
    # 查看pod节点
    [root@master k8s]# kubectl get pod -n dev 
    

    image-20211009083939857

    # 进入容器查看环境变量
    [root@master k8s]# kubectl exec -it -n dev pod-env -c busybox /bin/sh
    

    image-20211009084108365

    端口配置

    KIND:     Pod
    VERSION:  v1
    RESOURCE: ports <[]Object>
    FIELDS:
      name <string> # 端口名称,如果指定,必须保证name在pod中是唯一的
      containerPort <integer> # 容器要监听的端口(0<x<65536)
      hostPort <integer> # 容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
      hostIP <string>  # 要将外部端口绑定到的主机IP(一般省略)
      protocol <string>  # 端口协议。必须是UDP、TCP或SCTP。默认为“TCP”
    
    # 创建配置文件
    cat > pod-port.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-ports
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17.1 # 容器需要的镜像地址
          imagePullPolicy: IfNotPresent # 设置镜像拉取策略
          ports:
            - name: nginx-port # 端口名称,如果执行,必须保证name在Pod中是唯一的
              containerPort: 80 # 容器要监听的端口 (0~65536)
              protocol: TCP # 端口协议
    EOF
    
    [root@master k8s]# kubectl create -f pod-ports.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get pod -n dev 
    

    image-20211009091950922

    # 查看pod的IP和端口
    [root@master k8s]# kubectl get pod -n dev pod-ports -o yaml
    

    image-20211009092212108

    # 查看ip
    [root@master k8s]# kubectl get pod -n dev pod-ports -o wide	
    
    # 访问内部服务
    [root@master k8s]# curl 10.244.1.21:80
    

    image-20211009092351903

    资源限制

    • 容器中的程序要运行,肯定会占用一定的资源,比如CPU和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量的资源,导致其他的容器无法运行。针对这种情况,kubernetes提供了对内存和CPU的资源进行配额的机制,这种机制主要通过resources选项实现,它有两个子选项:

      • limits:用于限制运行的容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启。

      • requests:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动。

    • 可以通过上述两个选项设置资源上下限

    # 创建配置文件
    cat > por-resources.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-resoures
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - name: nginx-port
              containerPort: 80
              protocol: TCP
          resources:
            # 配置上限
            limits:
              memory: "10G"
              cpu: "4"
            # 配置下限
            requests:
              memory: "100M"
              cpu: "1"
    EOF
    
    [root@master k8s]# kubectl create -f pod-resoures.yaml 
    
    [root@master k8s]# kubectl get pod -n dev
    

    image-20211009094409802

    # 查看容器IP
    [root@master k8s]# kubectl get pod -n dev pod-resoures -o wide
    
    # 访问容器
    [root@master k8s]# curl 10.244.1.22:80
    

    image-20211009094622210

    # 现在修改容器资源下限故意将资源超出虚拟机配置
        requests:
              memory: "10Gi"
              cpu: "5"
    
    # 删除原有pod
    [root@master k8s]# kubectl delete -f pod-resoures.yaml 
    
    # 增加pod
    [root@master k8s]# kubectl create -f pod-resoures.yaml 
    
    # 查看
    [root@master k8s]# kubectl describe pod -n dev pod-resoures 
    

    image-20211009095053152

    Pod生命周期

    简介

    我们一般将Pod从创建到终止这段时间称之为Pod生命周期,其主要包含如下过程

    • Pod创建过程

    • 运行初始化容器过程(init container)

    • 运行主容器过程(main container)

      • 容器启动后钩子函数(post start),容器终止之前钩子函数(pre stop)
      • 容器的存活性探测(liveness probe),容器就绪性探测(readiness probe)
    • Pod终止过程

    live

    在Pod创建过程中会经历如下状态

    • 挂起(pending):Pod正在处于被调度到具体节点过程中或者拉取镜像的过程中
    • 运行(running):Pod已经被调度到某个节点之中并且有kubelet创建完成
    • 成功(Successded):Pod内部的所有容器都已经成功执行完毕并且不会再次重启
    • 失败(Fail):Pod内部所有容器都已经终止但是有一个容器终止失败,即返回非0的状态
    • 位置(Unknow):Apiserver无法获取pod信息一般由网络原因导致

    创建和终止过程

    创建过程

    • apiserver接收客户端或者kubelet创建pod的请求
    • apiserver将创建的pod信息存储到etcd中,然后将结果返回给客户端
    • apiserver开始反映pod的状态变化,其余节点通过 watch 机制监听pod信息状态变化
    • scheduler通过 watch 机制发现有pod需要被创建,通过一定算法计算出pod分配节点信息并且将结果返回给apiserver
    • node节点的kubelet接收创建信息启动docker并且将结果返回给apiserver
    • apiserver将pod信息存储到etcd中

    终止过程

    • apiserver接收用户删除pod指令
    • pod的状态信息会随着时间的推移而更新,在宽限其内(默认30S)状态为 dead 宽限期是因为pod中运行容器删除pod需要停止容器花费时间
    • 将pod状态标记为 terminating 状态
    • kubelet监控到pod对象转为 terminating 会启动关闭pod过程
    • 端点控制器会将pod从所匹配的service资源删除,由于pod都不存在了也不需要与service关联了
    • 如果pod定义了 pre stop 钩子函数,则在其状态为 terminating 状态的时候同步执行钩子函数
    • Pod对象中的容器进程收到停止信号
    • 若在宽限期内Pod还有运行的容器,则Pod会收到立即中止的信号
    • kubectl请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,此时Pod对于用户已经不可用了

    初始化容器

    初始化容器即在容器启动之前需要进行的准备工作,主要具备两大特征

    • 初始化容器必须运行完成直至结束,如果某个容器初始化失败,kubernetes会一直进行容器重启直至成功
    • 初始化容器必须按照定义的顺序执行且只有当前容器执行完毕才能执行下一个容器

    初始化容器运用场景

    • 提供主容器镜像中不具备的工具程序或自定义代码
    • 按照串行化启动容器,因此某个容器只有满足条件才可以启动成功

    此时假如我们运行nginx容器,但是要求nginx启动之前必须先运行mysql以及redis容器成功启动才可以启动nginx容器

    为了简化测试,事先规定好MySQL和Redis所在的IP地址分别为 10.1.1.1010.1.1.20(注意,这两个IP都不能ping通,因为环境中没有这两个IP)

    # 创建配置文件
    cat > pod-initcontainer.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-initcontainer
      namespace: dev
      labels:
        user: SR
    spec:
      containers: # 容器配置
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - name: nginx-port
              containerPort: 80
              protocol: TCP
          resources:
            limits:
              cpu: "2"
              memory: "10Gi"
            requests:
              cpu: "1"
              memory: "10Mi"
      initContainers: # 初始化容器配置 
        - name: test-mysql
          image: busybox:1.30
          command: ["sh","-c","until ping 10.1.1.10 -c 1;do echo waiting for mysql ...;sleep 2;done;"]
        - name: test-redis
          image: busybox:1.30
          command: ["sh","-c","until ping 10.1.1.20 -c 1;do echo waiting for redis ...;sleep 2;done;"]
    EOF
    
    # 运行
    [root@master k8s]# kubectl create -f pod-initcontainer.yaml 
    
    # 查看
    [root@master k8s]# kubectl get pod -n dev
    

    image-20211014182122317

    [root@master k8s]# kubectl describe -n dev pod pod-initcontainer 
    

    image-20211014182324919

    # 动态查看pod运行情况
    [root@master k8s]# kubectl get pod pod-initcontainer -n dev -w
    

    image-20211014182516042

    # 新开一个终端添加IP地址10.1.1.20
    [root@master k8s]# ifconfig ens33:10 10.1.1.10 netmask 255.255.255.0 up
    

    image-20211014183240624

    # 新开一个终端添加IP地址10.1.1.20
    [root@master k8s]# ifconfig ens33:20 10.1.1.20 netmask 255.255.255.0 up
    

    image-20211014183434738

    钩子函数

    钩子函数意外我们可以在容器创建之后与销毁之前执行某些动作帮助我们更好的管理容器

    钩子处理器支持三种方式定义动作

    • exec命令:在容器内执行命令

      ……
        lifecycle:
           postStart: 
              exec:
                 command:
                   - cat
                   - /tmp/healthy
      ……
      
    • tcpsocket:在当前容器尝试访问指定的socket

      …… 
         lifecycle:
            postStart:
               tcpSocket:
                  port: 8080
      ……
      
    • httpGet:在当前容器中向某url发起HTTP请求

      …… 
         lifecycle:
            postStart:
               httpGet:
                  path: / #URI地址
                  port: 80 #端口号
                  host: 192.168.109.100 #主机地址  
                  scheme: HTTP #支持的协议,http或者https
      ……
      

    接下来,以exec方式为例,演示下钩子函数的使用

    # 创建文件
    cat > pod-hook-exec.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-hook-exec
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "10Gi"
              cpu: "2"
            requests:
              memory: "10Mi"
              cpu: "1"
          ports:
            - containerPort: 80
              protocol: TCP
          lifecycle:
            postStart:
              exec: 
                # 容器启动之前执行命令
                command:
                  # 修改nginx的默认首页
                  [
                    "/bin/sh",
                    "-c",
                    "echo postStart ... > /usr/share/nginx/html/index.html",
                  ]
            preStop:
              # 容器停止执行命令
              exec:
                command: ["/usr/sbin/nginx", "-s", "quit"]
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-hook-exec.yaml 
    
    # 查看IP地址
    [root@master k8s]# kubectl get -n dev pod pod-hook-exec -o wide
    

    # 访问容器
    [root@master k8s]# curl 10.244.1.29
    

    image-20211014213944155

    容器探测

    容器探测主要检测容器能否正常对外工作,如果经过探测容器的状态不符合预期,则容器会被K8S移除不承担业务流量,在K8S中提供了存活性探测与就绪性探测。

    • liveness(存活性探测):检测容器是否正常运行,如果运行异常则会将容器重启

    • readiness(就绪性探测):检测容器能否正常接收请求,如果不能则不转发流量

    探测方式

    • exec:在容器内部执行命令,如果容器返回为非0的状态码则容器异常会被重启
    ……
      livenessProbe:
         exec:
            command:
              -	cat
              -	/tmp/healthy
    ……
    
    • tcpSocket:连接容器内部端口如果能正常连接则容器正常反之容器异常
    ……
       livenessProbe:
          tcpSocket:
             port: 8080
    ……
    
    • httpGet:对容器的url发起请求,如果请求状态码处于 200-399 之前则认为容器正常反之异常
    ……
       livenessProbe:
          httpGet:
             path: / #URI地址
             port: 80 #端口号
             host: 127.0.0.1 #主机地址
             scheme: HTTP #支持的协议,http或者https
    ……
    

    探测实验:exec

    # 创建文件
    cat > pod-liveness-exec.yaml << EOF
    kind: Pod
    metadata:
      name: pod-liveness-exec
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "10Gi"
              cpu: "2"
            requests:
              memory: "10Mi"
              cpu: "1"
          ports:
            - containerPort: 80
              protocol: TCP
          livenessProbe:
            exec:
              # 执行一个查看文件的命令,必须失败,因为根本没有这个文件
              command: ["/bin/cat", "/tmp/hello.txt"]
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-liveness-exec.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-liveness-exec -w
    

    image-20211014224853298

    # 查看详细信息
    [root@master k8s]# kubectl describe -n dev pod pod-liveness-exec 
    

    image-20211014225039662

    # 查看pod节点信息
    [root@master k8s]# kubectl get pod pod-liveness-exec -n dev
    

    image-20211014225334832

    探测实验:tcpSocket

    cat > pod-liveness-tcpsocket.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-liveness-tcpsocket
      namespace: dev
    
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
    
          resources:
            limits:
              memory: "10Gi"
              cpu: "2"
            requests:
              memory: "10Mi"
              cpu: "1"
          ports:
            - containerPort: 80
              protocol: TCP
          livenessProbe:
            # 探测8080端口但是容器内部未暴露8080因此容器异常
            tcpSocket:
              port: 8080
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-liveness-tcpsocket.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-liveness-tcpsocket -w
    

    image-20211014230232749

    # 查看详细信息
    [root@master k8s]# kubectl describe -n dev pod pod-liveness-tcpsocket 
    

    image-20211014230339322

    [root@master k8s]# kubectl get -n dev pod pod-liveness-tcpsocket 
    

    image-20211014230504692

    探测实验:httpGet

    # 创建配置文件
    cat > pod-liveness-httpget.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-liveness-httpget
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          resources:
            limits:
              memory: "10Gi"
              cpu: "2"
            requests:
              memory: "10Mi"
              cpu: "1"
          ports:
            - containerPort: 80
              protocol: TCP
          livenessProbe:
            # 其实就是访问http://127.0.0.1:80/hello
            httpGet:
              port: 80
              host: 127.0.0.1
              # 访问路径
              path: /hello
              # 访问方式
              scheme: HTTP
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-liveness-httpget.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-liveness-httpget -w
    

    image-20211014231535662

    # 查看详细信息
    [root@master k8s]# kubectl describe -n dev pod pod-liveness-httpget 
    

    image-20211014231717324

    [root@master k8s]# kubectl get -n dev pod pod-liveness-httpget 
    

    image-20211014232039173

    探测可选项

    '''
    在livenessProbe中包含一些可选项
    initialDelaySeconds    # 容器启动后等待多少秒执行第一次探测
    timeoutSeconds      # 探测超时时间。默认1秒,最小1秒
    periodSeconds       # 执行探测的频率。默认是10秒,最小1秒
    failureThreshold    # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
    successThreshold    # 连续探测成功多少次才被认定为成功。默认是1
    '''
    

    重启策略

    在容器探测中,一旦容器探测出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是由Pod的重启策略决定的,Pod的重启策略有3种,分别如下

    • Always:默认重启策略,即容器失效时候自动重启容器
    • OnFailure:容器终止运行且退出码不为0时候重启
    • Never:绝不重启会停止容器

    重启策略适用于Pod对象中的所有容器,首次需要重启的容器,将在其需要的时候立即进行重启,随后再次重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s,300s是最大的延迟时长。

    # 创建文件
    cat > pod-restart-policy.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-restart-policy
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "10Gi"
              cpu: "2"
            requests:
              memory: "10Mi"
              cpu: "1"
          ports:
            - containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              port: 80
              host: 127.0.0.1
              scheme: HTTP
              path: /
      restartPolicy: Never
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-restart-policy.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-restart-policy 
    

    image-20211014234817490

    # 查看创建过程
    [root@master k8s]# kubectl describe -n dev pod pod-restart-policy 
    

    image-20211014234944878

    Pod调度

    简介

    在默认情况下Pod是通过Scheduler通过一定的算法调度到相应的node节点上,这一过程人为是不能干扰的,但是在有时候我们希望控制pod所处节点位置,在K8S中为我们提供了Pod调度策略,我们可以通过Pod调度策略依据策略将Pod调度到指定的node节点上,在K8S中为我们提供了四种调度策略。

    调度策略

    • 自动调度:由Scheduler通过一定的算法自动调度到node节点上人为无法干预
    • 定向调度:通过nodename/nodeselector等调度到指定的node节点上
    • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity。
    • 污点(容忍)调度:Taints、Toleration

    定向调度

    简介

    在Pod节点上声明nodename或者nodeselector,使用nodename或者nodeselector将pod调度到指定的node上,这里的调度是强制的如果声明的node节点不存在依旧会将pod调度到该node节点上,但是pod会运行失败而已

    nodename

    nodeName用于强制约束将Pod调度到指定的name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点

    # 创建pod配置文件
    cat > pod-nodename.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodename
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          imagePullPolicy: IfNotPresent
          image: nginx:1.17.1
          ports:
            - containerPort: 80
              protocol: TCP
      # 指定将容器调度到node1节点
      nodeName: node1
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-nodename.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-nodename -o wide
    

    image-20211015143914204

    # 此时将nodename指定一个不存在的node节点上
    nodeName: node3
    
    # 查看node节点
    [root@master k8s]# kubectl get -n dev pod pod-nodename 
    

    image-20211015144329888

    nodeselector

    nodeSelector用于将Pod调度到添加了指定标签的Node节点上,它是通过kubernetes的label-selector机制实现的,换言之,在Pod创建之前,会由Scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将Pod调度到目标节点,该匹配规则是强制约束

    # 给node添加标签
    [root@master k8s]# kubectl label node node1 env=test
    
    [root@master k8s]# kubectl label node node2 env=pro
    
    # 查看标签
    [root@master k8s]# kubectl get node --show-labels 
    

    image-20211015145917462

    # 创建配置文件
    cat > pod-nodeselector << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodeselector
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
      # 配置标签选择器
      nodeSelector:
        # 选择标签
        env: test
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-nodeselector.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-nodeselector -o wide
    

    image-20211015150518480

    # 将上述标签配置一个不存在的标签
    env: dev
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-nodeselector -o wide
    

    image-20211015150737961

    # 查看详情
    [root@master k8s]# kubectl describe -n dev pod pod-nodeselector 
    

    image-20211015150836564

    亲和性调度

    简介

    在上述定向调度的时候如果node不满足pod选择条件,虽然pod依旧会被创建但是无法正常对外提供服务,即使集群中有可用的node节点依旧无法正常运行

    在K8S中提供了容器亲和性调度,其在 nodeSelector 基础上进行了扩展,如果当前node节点满足pod创建要求则会被创建到满足要求的节点上,如果没有节点满足要求会退而求其次即使节点不满足条件依旧可以被创建,这样保证了我们pod能够正常被创建对外提供服务。

    调度类型

    • nodeAffinity(node亲和性):以node为目标,解决pod可以调度到那些node节点
    • podAffinity(pod亲和性):以Pod为目标,解决Pod可以和那些已存在的Pod部署在同一个拓扑域中的问题。
    • podAntiAffinity(pod反亲和性):以Pod为目标,解决Pod不能和那些已经存在的Pod部署在同一拓扑域中的问题。

    关于亲和性和反亲和性的使用场景的说明:

    • 亲和性:如果两个应用频繁交互,那么就有必要利用亲和性让两个应用尽可能的靠近,这样可以较少因网络通信而带来的性能损耗。

    • 反亲和性:当应用采用多副本部署的时候,那么就有必要利用反亲和性让各个应用实例打散分布在各个Node上,这样可以提高服务的高可用性。

    nodeAffinity详解

    • 语法配置
    pod.spec.affinity.nodeAffinity
      requiredDuringSchedulingIgnoredDuringExecution  Node节点必须满足指定的所有规则才可以,相当于硬限制
        nodeSelectorTerms  节点选择列表
          matchFields   按节点字段列出的节点选择器要求列表  
          matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
            key    键
            values 值
            operator 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
            
      preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)     
        preference   一个节点选择器项,与相应的权重相关联
          matchFields 按节点字段列出的节点选择器要求列表
          matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
            key 键
            values 值
            operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt  
        weight 倾向权重,在范围1-100。
    
    • 使用案例
    - matchExpressions:
    	- key: env # 匹配存在标签的key为nodeenv的节点
    	  operator: Exists   
    	- key: env # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
    	  operator: In    
          values: ["xxx","yyy"]
        - key: env # 匹配标签的key为nodeenv,且value大于"xxx"的节点
          operator: Gt   
          values: "xxx"
    
    • 硬条件实验测试
    # 创建配置文件
    cat > pod-nodeaffinity-required << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodeaffinity-required
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
      # 配置亲和度
      affinity:
        # 选择节点亲和度
        nodeAffinity:
          # 选择硬限制
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              # 选择节点标签
              - matchExpressions:
                  # 匹配节点key=env value=xxx或者value=yyy的节点
                  - key: env
                    values:
                      - "xxx"
                      - "yyy"
                    operator: In
    EOF
    
    # 创建pod
    [root@master k8s]#  kubectl create -f pod-nodeaffinity-required.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-nodeaffinity-required -o wide
    

    image-20211015172132163

    # 查看详情
    [root@master k8s]# kubectl describe -n dev pod pod-nodeaffinity-required 
    

    image-20211015172229069

    # 将value中不存在的值修改为存在
    '''
    values:
      - "test"
      - "yyy"
    '''
    
    # 修改完毕之后查看pod节点
    [root@master k8s]# kubectl get -n dev pod pod-nodeaffinity-required -o wide
    

    image-20211015172621262

    • 软条件测试
    cat > pod-nodeaffinity-preferred.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodeaffinity-preferred
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 80
              protocol: TCP
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - preference: # 一个节点选择器项与相应的权重相关联
                matchExpressions:
                  - key: env
                    # 创建不存在的value
                    values:
                      - "xxx"
                      - "yyy"
                    operator: In
              weight: 1
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-nodeaffinity-preferred.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-nodeaffinity-preferred -o wide
    

    image-20211015173706680

    nodeAffinity的注意事项:

    • 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都满足,Pod才能运行在指定的Node上。

    • 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可。

    • 如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有的才能匹配成功。

    • 如果一个Pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的nodeAffinity的要求,则系统将忽略此变化。

    podAffinity详解

    podAffinity主要实现以运行的Pod为参照,实现让新创建的Pod和参照的Pod在一个区域的功能

    pod.spec.affinity.podAffinity
      requiredDuringSchedulingIgnoredDuringExecution # 硬限制
        namespaces # 指定参照pod的namespace
        topologyKey # 指定调度作用域
        labelSelector # 标签选择器 选择参照pod
          matchExpressions  # 按节点标签列出的节点选择器要求列表(推荐)
            key    键
            values 值
            operator # 关系符 支持In, NotIn, Exists, DoesNotExist.
          matchLabels    # 指多个matchExpressions映射的内容 
          
      preferredDuringSchedulingIgnoredDuringExecution # 软限制    
        podAffinityTerm # 选项
          namespaces
          topologyKey	# 位置拓扑键,用来判定拥有哪些标签的节点是同一位置以确定pod绑定在那个节点上
          labelSelector
             matchExpressions 
                key    键  
                values 值  
                operator
             matchLabels 
        weight 倾向权重,在范围1-1
    

    topologyKey用于指定调度的作用域,例如:

    • 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围。

    • 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。

    # 先创建参照pod
    
    cat > pod-podaffinity-target.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-podaffinity-target
      namespace: dev
      labels:
        podenv: pro # 设置标签用来选择pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 80
              protocol: TCP
      nodeName: node1
    
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-podaffinity-target.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-podaffinity-target -o wide --show-labels 
    

    image-20211015213719765

    # 创建硬限制
    cat > pod-podaffinity-requred.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-podaffinity-requred
      namespace: dev
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
    
          ports:
            - containerPort: 80
              protocol: TCP
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  # 匹配Key=podenv value=xxx或者value=yyy由于值不存在因此不能被正确的调度到节点上
                  - key: podenv
                    values:
                      - "xxx"
                      - "yyy"
                    operator: In
              # 以节点名字作为拓扑键
              topologyKey: kubernetes.io/hostname
    
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-podaffinity-requred.yaml
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-podaffinity-requred -o wide
    

    image-20211015215139644

    # 查看详情
    [root@master k8s]# kubectl describe -n dev pod pod-podaffinity-requred 
    

    image-20211015215646198

    # 将值修改为正确的 pro存在
     values:
       - "pro"
       - "yyy"
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-podaffinity-requred -o wide
    

    image-20211015215402230

    cat > pod-podaffinity-preferred.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-podaffinity-preferred
      namespace: dev
    
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                topologyKey: kubernetes.io/hostname
                namespaces:
                  - "dev"
                labelSelector:
                  matchExpressions:
                    - key: prodev
                      values:
                        - "xxx"
                        - "yyy"
                      operator: In
              weight: 1
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-podaffinity-preferred.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-podaffinity-preferred -o wide 
    

    image-20211015221423037

    podAffinityTerm详解

    podAntiAffinity主要实现以运行的Pod为参照,让新创建的Pod和参照的Pod不在一个区域的功能

    # 创建pod配置文件
    cat > pod-podantiaffinity-requred.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-podantiaffinity-requred
      namespace: dev
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 80
              protocol: TCP
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: podenv
                    # 只要key!=podenv values!=pro即可
                    values:
                      - "pro"
                    operator: In
              topologyKey: kubernetes.io/hostname
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-podantiaffinity-requred.yaml 
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod-podantiaffinity-requred -o wide
    

    image-20211015230023915

    污点和容忍

    前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定Pod是否要调度到指定的Node上,其实我们也可以站在Node的角度上,通过在Node上添加污点属性,来决定是否运行Pod调度过来Node被设置了污点之后就和Pod之间存在了一种相斥的关系,进而拒绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去。

    污点的格式为:key=value:effect,key和value是污点的标签,effect描述污点的作用,支持如下三个选项

    • PreferNoSchedule:K8S尽量避免将pod调度到具有该污点的node上,除非没有其余可用节点才会调度到污染节点上
    • NoSchedule:K8S不会将Pod调度到具有污染的node上,但是已经存在的node节点不会被影响
    • NoExecute:K8S不会将pod调度到具有污染的node上同时已经存在的pod也会被驱逐

    tainit

    语法

    # 设置污点
    kubectl taint node xxx key=value:effect
    
    # 删除污点
    kubectl taint node xxx key:effect-
    
    # 删除所有污点
    kubectl taint node xxx key-
    

    实验步骤

    • 首先关闭node2保证只有一个节点
    • 为node1节点设置一个污点:user=SR:PreferNoSchedule,然后创建Pod1(Pod1可以)
    • 修改node1节点污点为 user=SR:NoSchedule,然后创建pod2(pod1可以正常运行,pod2创建失败)
    • 修改node1节点污点为 user=SR:NoExecute, 然后创建pod3(三个都失败)
    污点
    # 停止node2
    [root@node2 ~]# systemctl status kubelet.service 
    

    image-20211016162157705

    # 创建污点
    [root@master k8s]# kubectl taint node node1 user=SR:PreferNoSchedule
    
    # 创建pod
    [root@master k8s]# kubectl run pod1 --image=1.17.1 -n dev
    
    # 查看pod
    [root@master k8s]# kubectl get -n dev pod pod1 -o wide
    

    image-20211016162709127

    # 修改node1污染属性为NoSchedule
    [root@master k8s]# kubectl taint node node1 user:PreferNoSchedule-		# 删除原有属性
    
    # 添加新属性
    [root@master k8s]# kubectl taint node node1 user=SR:NoSchedule
    
    # 创建pod2
    [root@master k8s]# kubectl run pod2 --image=nginx:1.17.1 -n dev
    
    # 查看pod
    [root@master k8s]# kubectl get pod pod1  pod2 -n dev -o wide 
    

    image-20211016163852035

    # 查看详情
    [root@master k8s]# kubectl describe -n dev pod pod2
    

    image-20211016163958716

    # 修改node1节点属性为NoExecute
    [root@master k8s]# kubectl taint node node1 user:NoSchedule-
    
    # 创建污染属性
    [root@master k8s]# kubectl taint node node1 user=SR:NoExecute
    
    # 创建pod
    [root@master k8s]# kubectl run pod3 -n dev --image=nginx:1.17.1
    

    image-20211016165023394

    # 查看详情
    [root@master k8s]# kubectl describe -n dev pod pod3
    

    image-20211016165106607

    使用kubeadm搭建的集群,默认就会给Master节点添加一个污点标记,所以Pod就不会调度到Master节点上。

    容忍

    我们可以在Node上添加污点用来拒绝Pod调度上来,但是如果就是想让一个Pod调度到一个有污点的Node上去,我们可以通过容忍来允许pod添加到有污染的node节点上。

    污点就是node拒绝pod加入节点,而容忍则是忽略某些pod允许加入节点

    kubectl explain pod.spec.tolerations
    ......
    FIELDS:
      key       # 对应着要容忍的污点的键,空意味着匹配所有的键
      value     # 对应着要容忍的污点的值
      operator  # key-value的运算符,支持Equal和Exists(默认)Exists对应的是key忽略value
      effect    # 对应污点的effect,空意味着匹配所有影响
      tolerationSeconds   # 容忍时间, 当effect为NoExecute时生效,表示已经存在的pod在Node上的停留时间
    

    当operator为Equal的时候,如果Node节点有多个Taint,那么Pod每个Taint都需要容忍才能部署上去。

    当operator为Exists的时候,有如下的三种写法:

    • 容忍指定的污点,污点带有指定的effect:

    • 容忍指定的污点,不考虑具体的effect:

    • 容忍一切污点(慎用):

      tolerations: # 容忍
        - key: "tag" # 要容忍的污点的key
          operator: Exists # 操作符
          effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同
          
       tolerations: # 容忍
          - key: "tag" # 要容忍的污点的key
          operator: Exists # 操作符
          
       tolerations: # 容忍
        - operator: Exists # 容忍一切规则
    

    在上面的污点中,已经给node1打上了NoExecute的污点,此时Pod是调度不上去的,此时可以通过在Pod中添加容忍,将Pod调度上去

    # 添加配置文件
    cat > pod-toleration.yaml << EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-toleration
      namespace: dev
      labels:
        user: SR
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
      # 添加容忍
      tolerations:
        # user=SR作用在NoExecute可以被添加
        - key: "user"
          value: "SR"
          operator: Equal
          effect: NoExecute
    EOF
    
    # 创建pod
    [root@master k8s]# kubectl create -f pod-toleration.yaml 
    
    # 查看pod
    [root@master flannel]# kubectl get -n dev pod pod-toleration -o wide
    

    image-20211018091923626

  • 相关阅读:
    面试系列三 如何保证消息不被重复消费
    面试系列二 消息队列的高可用性
    面试系列一 消息队列
    springcloud系列15 bus的使用
    C++ 参数传值 与 传引用
    [转] 写给立志做码农的大学生
    Python format 格式化函数
    [3] TensorFlow 深层神经网络
    [2] TensorFlow 向前传播算法(forward-propagation)与反向传播算法(back-propagation)
    Python 闭包
  • 原文地址:https://www.cnblogs.com/SR-Program/p/15350520.html
Copyright © 2011-2022 走看看