初识kubernetes第六周

一. Kubernetes Container、Pod、Namespace内存及CPU限制

1. 1 Container

  • CPU限制:指定容器可以使用的最大CPU资源量
  • CPU请求:指定容器正常运行所需的最小CPU资源
  • 内存限制:指定容器可以使用的最大内存
  • 内存请求:指定容器正常运行所需的最小内存
    需要在容器的创建文件中添加resources: requests(容器启动需要的最小资源)字段,和resources: limits(容器能使用的最大资源)字段,建议把启动容器的最小的资源和容器启动后可以使用的最大资源限制设置为一样
# vim case2-pod-memory-and-cpu-limit.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: limit-test-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: limit-test-pod
  template:
    metadata:
      labels:
        app: limit-test-pod
    spec:
      containers:
      - name: limit-test-container
        image: lorel/docker-stress-ng   # 压测的容器镜像
        resources:
          limits:      # 该容器最多可以使用的资源量
            cpu: "2"       # 最多可以使用2核CPU,其中1核cpu=1000毫核cpu,在yml文件的参数也可以写0.8 或者800m ,它俩是一样的
            memory: "512Mi"      # 最多可以使用512M内存
          requests:          # 启动容器所需的最小资源(启动所需不是马上要占用这么多,只是需要目标node节点资源需要满足容器所需的最小资源,容器才有可能调度到该node节点上)
            memory: "512Mi"       # 最少需要512M内存
            cpu: "2"      # 最少需要2核的cpu
        #command: ["stress"]
        args: ["--vm", "3", "--vm-bytes", "256M"]     #启用3个线程,每个线程占用256M内存

1.1.1 需要进行资源限制的原因

  • 如果没有进行资源限制,容器可以使用所在node节点的所有资源,可能导致发生故障,如内存可能发生OOM kill,没有做资源限制的容器被杀掉的可能性更大
  • 如果pod有突发性的活动,也可以巧妙的利用CPU资源,预防影响该节点的其它pod,把资源的请求和限制的所需资源设置为一样,也是为了防止pod由于突发性的活动,占用过多,该节点运行的所有容器镜像的最大资源限制大于了该node节点的资源,导致服务异常

1.2 Pod

LimitRange 是对具体某个Pod或容器的资源使用镜像限制

  • 限制namespace中每个pod或容器的最小与最大计算资源
  • 限制namespace中每个pod或容器计算资源request、limit之间的比例
  • 限制namespace中每个存储卷声明可使用的最小与最大存储空间
  • 设置namespace中容器默认计算资源的request、limit,并在运行时自动注入到容器中
# vim case3-LimitRange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: limitrange-magedu
  namespace: web
spec:
  limits:
  - type: Container       #限制的资源类型
    max:
      cpu: "2"            #限制单个容器的最大CPU
      memory: "2Gi"       #限制单个容器的最大内存
    min:
      cpu: "500m"         #限制单个容器的最小CPU
      memory: "512Mi"     #限制单个容器的最小内存
    default:
      cpu: "500m"         #默认单个容器的CPU限制
      memory: "512Mi"     #默认单个容器的内存限制
    defaultRequest:
      cpu: "500m"         #默认单个容器的CPU创建请求
      memory: "512Mi"     #默认单个容器的内存创建请求
    maxLimitRequestRatio:
      cpu: 2              #限制CPU limit/request比值最大为2  
      memory: 2         #限制内存limit/request比值最大为1.5
  - type: Pod
    max:
      cpu: "4"            #限制单个Pod的最大CPU
      memory: "4Gi"       #限制单个Pod最大内存
  - type: PersistentVolumeClaim
    max:
      storage: 50Gi        #限制PVC最大的requests.storage
    min:
      storage: 30Gi        #限制PVC最小的requests.storage

1.3 Namespace

  • 限定某个对象类型(如Pod、service)可创建对象的总数;
  • 限定某个对象类型可消耗的计算资源(CPU、内存)与存储资源(存储卷声明)总数
# vim case6-ResourceQuota-web.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: quota-web
  namespace: web
spec:
  hard:
    requests.cpu: "8"    #该命名空间的所有pod的CPU请求总和不超过8核CPU
    limits.cpu: "8"    #该命名空间的所有pod的CPU限制总和不超过8核cpu
    requests.memory: 8Gi    #该命名空间的所有pod的内存请求总和不超过8G
    limits.memory: 8Gi    #该命名空间的所有pod的内存限制总和不超过8G
    requests.nvidia.com/gpu: 4   #该命名空间的所有pod的NVIDIA GPU请求不超过4
    pods: "6"    #该命名空间的所有pod数量不超过6
    services: "6"  #该命名空间的所有pod的services数量不超过6

二. nodeSelector、nodeName、node亲和与反亲和

2.1 nodeSelector

nodeSelector 基于node标签选择器,将pod调度到指定的目的节点上。

  • 可用于基于服务类型干预Pod调度结果,如对磁盘I/O要求高的pod调度到SSD节点,对内存要求比较高的pod调度到内存较高的节点。
  • 也可以用于区分不同项目的pod,如将node添加不同项目的标签,然后区分调度

标签说明

#添加标签
# kubectl label nodes worker-01 project="web"    #其中worker-01为node节点,要填写kubectl get pod查看到的名字,不能直接填写node节点的ip地址

#查看
# kubectl get nodes worker-01
...
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=worker-01
                    kubernetes.io/os=linux
                    kubernetes.io/role=node
                    project=web

#删除标签
# kubectl label nodes worker-01 project-

yaml文件设置

# vim case1-nodeSelector.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine 
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
      nodeSelector:    # node标签选择,需要node节点同时有下面两个标签,pod才会调度过去
        project: web    # label字段project=web
        disktype: ssd    # disktype=ssd

2.2 nodeName

nodeName 是比亲和性或者 nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。如果 nodeName 字段不为空,调度器会忽略该 Pod, 而指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 使用 nodeName 规则的优先级会高于使用 nodeSelector 或亲和性与非亲和性的规则。

使用 nodeName 来选择节点的方式有一些局限性:

  • 如果所指定的节点不存在,则 Pod 无法运行,而且在某些情况下可能会被自动删除。
  • 如果所指定的节点无法提供用来运行 Pod 所需的资源,Pod 会失败, 而其失败原因中会给出是否因为内存或 CPU 不足而造成无法运行。
  • 在云环境中的节点名称并不总是可预测的,也不总是稳定的。
# vim case2-nodename.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      nodeName: 172.31.7.113    # nodeName,该pod只会调度到172.20.20.113的node节点上
      containers:
      - name: magedu-tomcat-app2-container
        image: tomcat:7.0.94-alpine 
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"

2.3 node亲和

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

  • requiredDuringSchedulingIgnoredDuringExecution #必须满足pod调度匹配条件,如果不满足则不进行调度
  • preferredDuringSchedulingIgnoredDuringExecution #倾向满足pod调度匹配条件,不满足的情况下会调度的不符合条件的Node上
  • IgnoreDuringExecution表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,也会继续运行当前的Pod。
  • Affinity与anti-affinity的目的也是控制pod的调度结果,但是相对于nodeSelector,Affinity(亲和)与anti-affinity(反亲和)的功能更加强大

affinity与nodeSelector对比:

  1. 亲和与反亲和对目的标签的选择匹配不仅仅支持and,还支持In、NotIn、Exists、DoesNotExist、Gt、Lt。
  • In:标签的值存在匹配列表中(匹配成功就调度到目的node,实现node亲和)
  • NotIn:标签的值不存在指定的匹配列表中(不会调度到目的node,实现反亲和)
  • Gt:标签的值大于某个值(字符串)
  • Lt:标签的值小于某个值(字符串)
  • Exists:指定的标签存在
  1. 可以设置软匹配和硬匹配,在软匹配下,如果调度器无法匹配节点,仍然将pod调度到其它不符合条件的节点。
  2. 还可以对pod定义亲和策略,比如允许哪些pod可以或者不可以被调度至同一台node。

注意:

  • 如果定义一个nodeSelectorTerms(条件)中通过一个matchExpressions基于列表指定了多个operator条件,则只要满足其中一个条件,就会被调度到相应的节点上,即or的关系,即如果nodeSelectorTerms下面有多个条件的话,只要满足任何一个条件就可以了。
  • 如果定义一个nodeSelectorTerms中都通过一个matchExpressions(匹配表达式)指定key匹配多个条件,则所有的目的条件都必须满足才会调度到对应的节点,即and的关系,即如果matchExpressions有多个选项的话,则必须同时满足所有这些条件才能正常调度。
# requiredDuringSchedulingIgnoredDuringExecution硬亲和
# vim case3-1.1-nodeAffinity-requiredDuring-matchExpressions.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度 
              - key: disktype
                operator: In
                values:
                - ssd # 只有一个value是匹配成功也可以调度
                - xxx
            - matchExpressions: #匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度 
              - key: project
                operator: In
                values:
                - mmm  #即使这俩条件都匹配不上也可以调度,即多个matchExpressions只要有任意一个能匹配任何一个value就可以调用。
                - nnn

# preferredDuringSchedulingIgnoredDuringExecution软亲和
# vim case3-2.2-nodeAffinity-requiredDuring-preferredDuring.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:  #可以同时设置软亲和与硬亲和
          requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
            nodeSelectorTerms:
            - matchExpressions: #硬匹配条件1
              - key: "kubernetes.io/role" 
                operator: NotIn
                values:
                - "master" #硬性匹配key 的值kubernetes.io/role不包含master的节点,即绝对不会调度到master节点(node反亲和)
          preferredDuringSchedulingIgnoredDuringExecution: #软亲和
          - weight: 80    #软亲和条件1,,weight值越大优先级越高,越优先匹配调度
            preference: 
              matchExpressions: 
              - key: project 
                operator: In 
                values: 
                  - web
          - weight: 60    #软亲和条件2,在条件1不满足时匹配条件2
            preference: 
              matchExpressions: 
              - key: disktype
                operator: In 
                values: 
                  - hdd

# weight字段,其取值范围是 1 到 100。 当调度器找到能够满足 Pod 的其他调度请求的节点时,调度器会遍历节点满足的所有的偏好性规则, 并将对应表达式的 weight 值加和。
#最终的加和值会添加到该节点的其他优先级函数的评分之上。 在调度器为 Pod 作出调度决定时,总分最高的节点的优先级也最高。

2.4 node反亲和

# cat case3-3.1-nodeantiaffinity.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions: #匹配条件1
              - key: disktype
                operator: NotIn #调度的目的节点没有key为disktype且值为hdd的标签
                values:
                - hdd #绝对不会调度到含有label的key为disktype且值为hdd的节点,即会调度到没有key为disktype且值为hdd的节点

三. pod亲和与反亲和、污点与容忍、驱逐

3.1 pod亲和与反亲和

Pod Affinity与anti-affinity简介:

  • Pod亲和性与反亲和性可以基于已经在node节点上运行的Pod的标签来约束新创建的Pod可以调度到的目的节点,注意不是基于node上的标签而是使用的已经运行在node上的pod标签匹配。
  • 其规则的格式为如果 node节点 A已经运行了一个或多个满足调度新创建的Pod B的规则,那么新的Pod B在亲和的条件下会调度到A节点上,而在反亲和性的情况下则不会调度到A节点上。
  • 其中规则表示一个具有可选的关联命名空间列表的LabelSelector,之所以Pod亲和与反亲和可以通过LabelSelector选择namespace,是因为Pod是命名空间限定的,而node不属于任何nemespace,所以node的亲和与反亲和不需要namespace,因此作用于Pod标签的标签选择算符必须指定选择算符应用在哪个命名空间。
  • 从概念上讲,node节点是一个拓扑域(具有拓扑结构的域),比如k8s集群中的单台node节点、一个机架、云供应商可用区、云供应商地理区域等,可以使用topologyKey来定义亲和或者反亲和的颗粒度是node级别还是可用区级别,以便kubernetes调度系统用来识别并选择正确的目的拓扑域

注意:

  • Pod 间亲和性和反亲和性都需要相当的计算量,因此会在大规模集群中显著降低调度速度。 不建议在包含数百个节点的集群中使用这类设置。
  • Pod 反亲和性需要节点上存在一致性的标签。换言之, 集群中每个节点都必须拥有与 topologyKey 匹配的标签。 如果某些或者所有节点上不存在所指定的 topologyKey 标签,调度行为可能与预期的不同。

3.1.1 Pod Affinity与anti-affinity类型

与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:

  • requiredDuringSchedulingIgnoredDuringExecution
  • preferredDuringSchedulingIgnoredDuringExecution
  1. Pod 亲和性与反亲和性的合法操作符(operator)有 In、NotIn、Exists、DoesNotExist。
  2. 在Pod亲和性配置中,在requiredDuringSchedulingIgnoredDuringExecution和
    preferredDuringSchedulingIgnoredDuringExecution中,topologyKey不允许为空(Empty topologyKey is not allowed.)。
  3. 在Pod反亲和性中配置中,requiredDuringSchedulingIgnoredDuringExecution和
    preferredDuringSchedulingIgnoredDuringExecution 中,topologyKey也不可以为空(Empty topologyKey is not allowed.)。
  4. 对于requiredDuringSchedulingIgnoredDuringExecution要求的Pod反亲和性,准入控制器
    LimitPodHardAntiAffinityTopology被引入以确保topologyKey只能是 kubernetes.io/hostname,如果希望 topologyKey 也可用于其他定制拓扑逻辑,可以更改准入控制器或者禁用。
  5. 除上述情况外,topologyKey 可以是任何合法的标签键。

3.1.2 pod亲和

#创建nginx测试pod
# vim case4-4.1-nginx.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: python-nginx-deployment-label
  name: python-nginx-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-nginx-selector
  template:
    metadata:
      labels:
        app: python-nginx-selector
        project: python
    spec:
      containers:
      - name: python-nginx-container
        image: nginx:1.20.2-alpine
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          protocol: TCP
          name: http
        - containerPort: 443
          protocol: TCP
          name: https
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: python-nginx-service-label
  name: python-nginx-service
  namespace: web
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30014
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
    nodePort: 30453
  selector:
    app: python-nginx-selector
    project: python #一个或多个selector,至少能匹配目标pod的一个标签

# kubectl apply -f case4-4.1-nginx.yaml
# kubectl get pod -n web
NAME                                          READY   STATUS      RESTARTS      AGE
python-nginx-deployment-748685f845-c58tb      1/1     Running     0             24s
# kubectl get pod python-nginx-deployment-748685f845-c58tb -n web --show-labels -o wide 
NAME                                       READY   STATUS    RESTARTS   AGE    IP              NODE        NOMINATED NODE   READINESS GATES   LABELS
python-nginx-deployment-748685f845-c58tb   1/1     Running   0          112s   10.200.36.125   worker-01   <none>           <none>            app=python-nginx-selector,pod-template-hash=748685f845,project=python

#软亲和与硬亲和
# vim case4-4.2-podaffinity-preferredDuring.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAffinity:  #Pod亲和
          #requiredDuringSchedulingIgnoredDuringExecution: #硬亲和,必须匹配成功才调度,如果匹配失败则拒绝调度。
          preferredDuringSchedulingIgnoredDuringExecution: #软亲和,能匹配成功就调度到一个topology,匹配不成功会由kubernetes自行调度。
          - weight: 100
            podAffinityTerm:
              labelSelector: #标签选择
                matchExpressions: #正则匹配
                - key: project
                  operator: In
                  values:
                    - python
              topologyKey: kubernetes.io/hostname 
              namespaces:
                - web

# cat case4-4.3-podaffinity-requiredDuring.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: magedu
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
          - labelSelector:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - python
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - web

硬亲和:后面创建的tomcat pod只调度到pod标签中key为project,value值为python的node上,即与nginx调度到同一个node上。

软亲和:后面创建的tomcat pod尽可能调度到pod标签中key为project,value值为python的node上,即与nginx调度到同一个node上,若无法匹配,则有kubernetes自行调度。

3.1.3 pod反亲和

# vim case4-4.4-podAntiAffinity-requiredDuring.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAntiAffinity:    #pod反亲和
          requiredDuringSchedulingIgnoredDuringExecution:   #硬反亲和
          - labelSelector:
              matchExpressions:
              - key: project
                operator: In
                values:
                  - python
            topologyKey: "kubernetes.io/hostname"
            namespaces:
              - web


# cat case4-4.5-podAntiAffinity-preferredDuring.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app2-deployment-label
  name: web-tomcat-app2-deployment
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-tomcat-app2-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app2-selector
    spec:
      containers:
      - name: web-tomcat-app2-container
        image: tomcat:7.0.94-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:   #软反亲和
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: project 
                  operator: In
                  values:
                    - pythonx
              topologyKey: kubernetes.io/hostname 
              namespaces: 
                - web

硬反亲和:后创建的tomcat pod不调度到pod标签中key为project,value值为python的node上,即不与nginx调度到同一个node上。

软反亲和:后创建的tomcat pod尽可能不调度到pod标签中key为project,value值为python的node上,即尽可能不与nginx调度到同一个node上。

3.2 污点与容忍

  • 污点(Taint)用于node节点排斥pod调度,与亲和的作用是完全相反的,即taint的node和pod是排斥调度关系。
  • 容忍(Toleration) 是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。 容忍度允许调度但并不保证调度:作为其功能的一部分, 调度器也会评估其他参数。

污点和容忍(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。

3.2.1 污点

污点三种类型
NoScheduler:表示k8s不会将pod调度具有该污点的Node上

PreferNoScheduler:表示k8s尽量避免将pod调度到具有该污点的node上

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

设置方法

#添加污点
# kubectl taint node 172.20.20.113 key1=value1:NoSchedule

#查看污点
# kubectl describe nodes 172.20.20.113 
...
Taints:             key1=value1:NoSchedule

#取消污点
# kubectl taint node 172.20.20.113 key1:NoSchedule-

3.2.2 容忍

定义pod的容忍度(即可以接收node的哪些污点),容忍后可以将pod调度至含有该污点的node。

基于operator的污点匹配:

  • 如果operator是Equal,则需要指定value并且value的值需要等于tolerations的key。
  • 如果operator的Exists,则容忍度不需要value而是直接匹配污点类型
# vim case5.1-taint-tolerations.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app1-deployment-label
  name: web-tomcat-app1-deployment
  namespace: web
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web-tomcat-app1-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app1-selector
    spec:
      containers:
      - name: web-tomcat-app1-container
        image: tomcat:7.0.93-alpine 
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
      tolerations: 
      - key: "key1"
        operator: "Equal"    # 当operator是Equal需要指定value并且value的值需要等于tolerations的key,如果operator是Exists,则容忍度不需要value而是直接匹配污点类型
        value: "value1"
        effect: "NoSchedule"

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: web-tomcat-app1-service-label
  name: web-tomcat-app1-service
  namespace: web
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    #nodePort: 40003
  selector:
    app: web-tomcat-app1-selector

注意:
存在两种特殊情况:

  1. 如果一个容忍度的 key 为空且 operator 为 Exists, 表示这个容忍度与任意的 key、value 和 effect 都匹配,即这个容忍度能容忍任何污点。
  2. 如果 effect 为空,则可以与所有键名 key1 的效果相匹配。

3.3 驱逐

节点压力驱逐是 kubelet 主动终止 Pod, 以回收节点上内存、磁盘空间等资源的过程。kubelet 监控集群节点的内存、磁盘空间和文件系统的 inode 等资源。 当这些资源中的一个或者多个达到特定的消耗水平, kubelet 可以主动地使节点上一个或者多个 Pod 强制驱逐,以防止当前node节点资源无法正常分配而引发的OOM(OutOfMemory)。

3.3.1 驱逐信号

驱逐信号是特定资源在特定时间点的当前状态。 kubelet 使用驱逐信号,通过将信号与驱逐条件进行比较来做出驱逐决定, 驱逐条件是节点上应该可用资源的最小量。

kubelet 使用以下驱逐信号:

  • memory.available
    node节点可用内存,默认<100M

  • nodefs
    是节点的主要文件系统,用于保存本地磁盘卷、emptyDir、日志存储等数据,默认是/var/lib/kubelet/,或者是kubelet通过--root-dir指定的磁盘挂载目录
    nodefs.available :nodefs的可用空间,默认<10%
    nodefs.inodesFree:nodefs的可用inode,默认<5%

  • imagefs
    可选文件系统,用于给容器提供运行时存储容器镜像和容器可写层
    imagefs.available:imagefs的磁盘空间可用百分比,默认<15%
    imagefs.inodesFree:imagefs的inode可用百分比

  • pid.available
    可用pid百分比

# cat /var/lib/kubelet/config.yaml 
...
evictionHard:
  imagefs.available: 15%
  memory.available: 300Mi
  nodefs.available: 10%
  nodefs.inodesFree: 5%

3.3.2 驱逐条件

可以为 kubelet 指定自定义驱逐条件,以便在作出驱逐决定时使用。驱逐条件的形式为 [eviction-signal][operator][quantity],其中:

  • eviction-signal 节点驱逐触发信号,进行判断是否驱逐,如通过cgroupfs获取memory.available的值来进行下一步匹配。
  • operator 操作符,通过操作符对比条件匹配资源量是否触发驱逐, 比如 <(小于)。
  • quantity 使用量,例如 1Gi。 quantity 的值必须与 Kubernetes 使用的数量表示相匹配,可以使用文字值或百分比(%)。

例如,如果一个节点的总内存为 10Gi 并且你希望在可用内存低于 1Gi 时触发驱逐, 则可以将驱逐条件定义为 memory.available<10% 或 memory.available< 1G,但两者不能同时使用。

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

可以使用以下标志来配置软驱逐条件:

  • eviction-soft:软驱逐触发条件,如 memory.available<1.5Gi, 如果驱逐条件持续时长超过指定的宽限期,可以触发 Pod 驱逐。
  • eviction-soft-grace-period:软驱逐宽限期, 如 memory.available=1m30s,定义软驱逐条件在触发 Pod 驱逐之前必须保持多长时间。
  • eviction-max-pod-grace-period:在满足软驱逐条件而终止 Pod 时使用的最大允许宽限期(以秒为单位)。

硬驱逐
硬驱逐条件没有宽限期。当达到硬驱逐条件时, kubelet 会立即杀死 pod并驱逐。
可以使用 eviction-hard 标志来配置硬驱逐条件, 例如 memory.available<1Gi,默认配置路径在/var/lib/kubelet/config.yaml

kubelet 具有以下默认硬驱逐条件(可以自行调整):
memory.available<100Mi
nodefs.available<10%
imagefs.available<15%
nodefs.inodesFree<5%(Linux 节点)

只有在没有更改任何参数的情况下,硬驱逐阈值才会被设置成这些默认值。 如果更改了任何参数的值,则其他参数的取值不会继承其默认值设置,而将被设置为零。 为了提供自定义值,应该分别设置所有阈值。

3.3.3 驱逐顺序

用于当node节点资源不足的时候自动将pod进行强制驱逐,以保证当前node节点的正常运行。

kubelet按QoS(服务质量等级)顺序排列和驱逐Pod:

  1. 首先考虑资源使用量超过其请求的BestEffort或Burstable Pod。 这些 Pod 会根据它们的优先级以及它们的资源使用级别超过其请求的程度被逐出。
  2. 资源使用量少于请求量的Guaranteed Pod 和Burstable Pod 根据其优先级被最后驱逐。
Guaranteed: #limits和request的值相等,等级最高、最后被驱逐
 resources:
 limits:
 cpu: 500m
 memory: 256Mi
 requests:
 cpu: 500m
 memory: 256Mi

Burstable: #limit和request不相等,等级折中、中间被驱逐
 resources:
 limits:
 cpu: 500m
 memory: 256Mi
 requests:
 cpu: 256m
 memory: 128Mi

sBestEffort: #没有限制,即resources为空,等级最低、最先被驱逐

四. 搭建ELK及kafka日志收集环境

ELK是Elasticsearch、Logstash和Kibana这三个开源项目的首字母缩写。Elasticsearch是一个搜索和分析引擎。Logstash是服务端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到Elasticsearch等“存储库”中。Kibana则可以让用户在Elasticsearch中使用图形和图表对数据进行可视化。

Elastic Stack是ELK Stack的更新换代产品。
日志收集流程


image.png

主机信息


image.png

主机先初始化完成

4.1 部署Elasticsearch

4.1.1 下载Elasticsearch

Elasticsearch依赖java环境,直接下载带jdk环境的安装包

#下载安装包
# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/7.x/apt/pool/main/e/elasticsearch/elasticsearch-7.12.1-amd64.deb

#安装
# dpkg -i elasticsearch-7.12.1-amd64.deb

4.1.2 修改服务配置

# egrep -v ^# /etc/elasticsearch/elasticsearch.yml 
cluster.name: elk-cluster    #集群名称
node.name: node-1    #当前节点名称
path.data: /var/log/elasticsearch    #ES数据保存位置
path.logs: /var/log/elasticsearch    #ES日志保存位置
network.host: 172.20.20.21    #监听地址
http.port: 9200    #监听端口
discovery.seed_hosts: ["172.20.20.21", "172.20.20.22", "172.20.20.23"]    #集群node节点发现列表
cluster.initial_master_nodes: ["172.20.20.21", "172.20.20.22", "172.20.20.23"]    #集群初始化可以选举位master节点列表
action.destructive_requires_name: true    设置是否可以通过正则或者_all删除或关闭索引库,默认true表示必须需要显示指定索引库名称,生产环境建议设置true,删除索引库

#集群其余两台也照着这样修改配置

其它可选配置

# cat /etc/elasticsearch/elasticsearch.yml
...
bootstrap.memory_lock: ture    #锁定内存
# cat /etc/elasticsearch/jvm.options
...
 -Xms4g     #最小内存限制
 -Xmx4g     #最大内存限制

#建议生产开启,但如果服务器没有连续的空闲内存空间,有时开启可能导致服务无法启动

4.1.3 启动服务

#启动服务,并设置开机自启
# systemctl start elasticsearch.service
# systemctl enable elasticsearch.service

4.1.4 检查服务端口

# ss -ntpl
State  Recv-Q Send-Q         Local Address:Port Peer Address:Port Process                                    
...
LISTEN 0      4096   [::ffff:172.20.20.21]:9200            *:*     users:(("java",pid=8778,fd=309))          
LISTEN 0      4096   [::ffff:172.20.20.21]:9300            *:*     users:(("java",pid=8778,fd=281))          

4.1.5 安装ElasticsearchHead插件

  1. 进入谷歌商店,直接搜索Elasticsearch Head插件,然后点添加


    image.png
  2. 选择扩展程序->Elasticsearch Head


    image.png
  3. 新建连接,输入Elasticsearch IP:端口


    image.png
  4. 查看Elasticsearch集群


    f2e7d4135d522334932fba233684a0b.png

4.2 Kibana

4.2.1 下载并安装Kibana

#下载安装包
# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/7.x/apt/pool/main/k/kibana/kibana-7.12.1-amd64.deb

#安装
# dpkg -i kibana-7.12.1-amd64.deb

4.2.2 修改服务配置

# egrep -v ^# /etc/kibana/kibana.yml 
server.port: 5601    #监听端口

server.host: "172.20.20.21"    #监听地址 


elasticsearch.hosts: ["http://172.20.20.22:9200"]    #Elasticsearch地址

i18n.locale: "zh-CN"    #web界面语言

4.2.3 启动服务并设置开机自启

# systemctl start kibana.service

# systemctl enable kibana.service

4.2.4 查看服务状态

访问 http://172.20.20.21:5601


6744b090c3a0e588aa627e921de9552.png

4.2.5 验证Elasticsearch head插件数据

Kibana自动生成隐藏索引


e4eb.png

4.3 Logstash

下载Logstash并安装

# 安装java环境
# apt install openjdk-8-jdk

#下载
# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/7.x/apt/pool/main/l/logstash/logstash-7.12.1-amd64.deb
 
#安装
# dpkg -i logstash-7.12.1-amd64.deb

暂时不添加配置,后面使用的时候添加

4.4 zookeeper

4.4.1 下载安装zookeeper

#先安装java环境
# apt update
# apt install openjdk-8-jdk

#下载zookeeper
# wget https://archive.apache.org/dist/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz

# mkdir -p /apps
# tar xvf apache-zookeeper-3.6.3-bin.tar.gz -C /apps
# ln -sv /apps/apache-zookeeper-3.6.3-bin /apps/zookeeper

4.4.2 修改配置

# cd /apps/zookeeper/conf/
# cp zoo_sample.cfg zoo.cfg

# egrep -v ^# zoo.cfg 
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper
clientPort=2181

server.1=172.20.20.25:2888:3888
server.2=172.20.20.26:2888:3888
server.3=172.20.20.27:2888:3888

#分别在三个节点创建myid,分别为1,2,3,取自配置文件中server后面的数字
# mkdir /data/zookeeper -p
# echo 1 > /data/zookeeper/myid

4.4.3 启动服务并验证

#启动
# /apps/zookeeper/bin/zkServer.sh start

#验证
root@kafka1:/apps/zookeeper# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower

root@kafka2:/apps/zookeeper/conf# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: leader

root@kafka3:/apps/zookeeper/conf# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower

4.5 kafka

4.5.1 下载并解压

# wget https://archive.apache.org/dist/kafka/3.1.1/kafka_2.13-3.1.1.tgz
# tar xvf kafka_2.13-3.1.1.tgz  -C /apps/
# ln -sv /apps/kafka_2.13-3.1.1 /apps/kafka

4.5.2 修改服务配置

# egrep -v ^# server.properties 
broker.id=103    #每个broker节点不相同
listeners=PLAINTEXT://172.20.20.27:9092    #设置监听地址和端口
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/data/kafka-logs     #kafka数据目录
num.partitions=1
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=172.20.20.25:2181,172.20.20.26:2181,172.20.20.27:2181    #zookeeper集群地址
zookeeper.connection.timeout.ms=18000    #zookeeper连接超时时间
#创建数据目录
mkdir -p /data/kafka-logs

4.5.3 启动服务和验证

#启动
# /apps/kafka/bin/kafka-server-start.sh -daemon /apps/kafka/config/server.properties

#检查
# ss -ntpl
State  Recv-Q Send-Q         Local Address:Port  Peer Address:PortProcess  
...                                  
LISTEN 0      50     [::ffff:172.20.20.27]:9092             *:*    users:(("java",pid=11522,fd=144))         
LISTEN 0      50                         *:2181             *:*    users:(("java",pid=10846,fd=65))          
LISTEN 0      50                         *:42981            *:*    users:(("java",pid=10846,fd=60))          
LISTEN 0      50                         *:35817            *:*    users:(("java",pid=11522,fd=126))         
LISTEN 0      50     [::ffff:172.20.20.27]:3888             *:*    users:(("java",pid=10846,fd=74))          
LISTEN 0      50                         *:8080             *:*    users:(("java",pid=10846,fd=69))          

4.5.4 验证元数据

本地电脑安装offsetexplorer后,新建连接
配置kafka、zookeeper信息


image.png

配置kafka信息


image.png

查看


c5cc1cfc07b892f11cc0ed1aed077fc.png

五. 实现daemonset和sidcar日志收集

5.1 daemonset日志收集

daemonset日志收集架构


b3dbf82c5eadf6f7e4285bfd96aa35a.png

5.1.1 构建Logstash镜像

编写Dockerfile文件

# vim Dockerfile 
FROM logstash:7.12.1

USER root
WORKDIR /usr/share/logstash 
#RUN rm -rf config/logstash-sample.conf
ADD logstash.yml /usr/share/logstash/config/logstash.yml
ADD logstash.conf /usr/share/logstash/pipeline/logstash.conf

准备配置文件

# vim logstash.yml 
http.host: "0.0.0.0"
#xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]

# vim logstash.conf 
input {
  file {
    #path => "/var/lib/docker/containers/*/*-json.log" #docker
    path => "/var/log/pods/*/*/*.log"
    start_position => "beginning"
    type => "jsonfile-daemonset-applog"
  }

  file {
    path => "/var/log/*.log"
    start_position => "beginning"
    type => "jsonfile-daemonset-syslog"
  }
}

output {
  if [type] == "jsonfile-daemonset-applog" {
    kafka {
      bootstrap_servers => "${KAFKA_SERVER}"
      topic_id => "${TOPIC_ID}"
      batch_size => 16384  #logstash每次向ES传输的数据量大小,单位为字节
      codec => "${CODEC}" 
   } }

  if [type] == "jsonfile-daemonset-syslog" {
    kafka {
      bootstrap_servers => "${KAFKA_SERVER}"
      topic_id => "${TOPIC_ID}"
      batch_size => 16384
      codec => "${CODEC}" #系统日志不是json格式
  }}
}

构建镜像并上传至本地仓库

# vim build-commond.sh 
#!/bin/bash

nerdctl build -t harbor.zhao.net/baseimages/logstash:v7.12.1-json-file-log-v1 .
nerdctl push harbor.zhao.net/baseimages/logstash:v7.12.1-json-file-log-v1

# bash build-commond.sh

5.1.2 创建daemonset收集任务

准备yaml文件

# vim 2.DaemonSet-logstash.yaml 
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: logstash-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: logstash-logging
spec:
  selector:
    matchLabels:
      name: logstash-elasticsearch
  template:
    metadata:
      labels:
        name: logstash-elasticsearch
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: logstash-elasticsearch
        image: harbor.zhao.net/baseimages/logstash:v7.12.1-json-file-log-v1 
        env:
        - name: "KAFKA_SERVER"
          value: "172.20.20.25:9092,172.20.20.26:9092,172.20.20.27:9092"
        - name: "TOPIC_ID"
          value: "jsonfile-log-topic"
        - name: "CODEC"
          value: "json"
        volumeMounts:
        - name: varlog   #定义宿主机系统日志挂载路径
          mountPath: /var/log   #宿主机系统日志挂载点
        - name: varlibdockercontainers   #定义容器日志挂载路径,和logstash配置文件中的收集路径保持一直
          #mountPath: /var/lib/docker/containers   #docker挂载路径
          mountPath: /var/log/pods   #containerd挂载路径,此路径与logstash的日志收集路径必须一致
          readOnly: false
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log   #宿主机系统日志
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers   #docker的宿主机日志路径
          path: /var/log/pods   #containerd的宿主机日志路径

查看pod

# kubectl get pod -n kube-system -o wide
NAME                                       READY   STATUS    RESTARTS      AGE     IP               NODE            NOMINATED NODE   READINESS GATES
...
logstash-elasticsearch-5f77z               1/1     Running   0             5m27s   10.200.36.65     worker-01       <none>           <none>
logstash-elasticsearch-652mm               1/1     Running   0             5m27s   10.200.159.131   master-01       <none>           <none>
logstash-elasticsearch-7rtgs               1/1     Running   0             5m27s   10.200.107.230   172.20.20.113   <none>           <none>
logstash-elasticsearch-ggj8r               1/1     Running   0             5m27s   10.200.135.195   172.20.20.103   <none>           <none>
logstash-elasticsearch-qdbhp               1/1     Running   0             3m2s    10.200.169.190   worker-02       <none>           <none>
logstash-elasticsearch-tz44d               1/1     Running   0             5m27s   10.200.224.3     master-02       <none>           <none>

5.1.3 验证kafka数据

登录kafka工具,查看Logstash收集日志

  • 修改类型为Sting


    a1e4b2978e25665dd4f01b388d13725.png
  • 查看Logstash收集日志内容


    b3e525b5a69682737edda0b0967dfaf.png

5.1.4 配置Logstash服务器

root@logstash1:/etc/logstash/conf.d# cat daemonset-log-es.conf 
input {
  kafka {
    bootstrap_servers => "172.20.20.25:9092,172.20.20.26:9092,172.20.20.27:9092"
    topics => ["jsonfile-log-topic"]
    codec => "json"
  }
}




output {
  #if [fields][type] == "app1-access-log" {
  if [type] == "jsonfile-daemonset-applog" {
    elasticsearch {
      hosts => ["172.20.20.21:9200","172.20.20.22:9200","172.20.20.23:9200"]
      index => "jsonfile-daemonset-applog-%{+YYYY.MM.dd}"
    }}

  if [type] == "jsonfile-daemonset-syslog" {
    elasticsearch {
      hosts => ["172.20.20.21:9200","172.20.20.22:9200","172.20.20.23:9200"]
      index => "jsonfile-daemonset-syslog-%{+YYYY.MM.dd}"
        }}
}

#重启服务
# systemctl restart logstash.service

5.1.5 验证Elasticsearch数据

Elasticsearch Head插件查看索引


7b67f2b56d30a8cee7a15b60f11d362.png

5.1.6 创建Kibana索引

078fa7229d3ca310ed0afb25068910d.png
image.png
image.png
99ba5e9cf850b977e2802d6e0dbd442.png

如上,分别创建jsonfile-daemonset-applog-和jsonfile-daemonset-syslog-(名字最后加*号,做匹配)的索引,完成后如下


image.png

5.1.7 Kibana展示收集日志

421009c2308604d70596327d0befd31.png
image.png

5.2 sidcar日志收集

sidcar日志收集架构


c037cc90b787af219e17590b91d2e81.png

5.2.1 构建sidcar镜像

准备Dockerfile文件

# vim Dockerfile 
FROM logstash:7.12.1
USER root
WORKDIR /usr/share/logstash 
ADD logstash.yml /usr/share/logstash/config/logstash.yml
ADD logstash.conf /usr/share/logstash/pipeline/logstash.conf

准备配置文件

# vim logstash.yml 
http.host: "0.0.0.0"
#xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]

# vim logstash.conf 
input {
  file {
    path => "/var/log/applog/catalina.out"
    start_position => "beginning"
    type => "app1-sidecar-catalina-log"
  }
  file {
    path => "/var/log/applog/localhost_access_log.*.txt"
    start_position => "beginning"
    type => "app1-sidecar-access-log"
  }
}

output {
  if [type] == "app1-sidecar-catalina-log" {
    kafka {
      bootstrap_servers => "${KAFKA_SERVER}"
      topic_id => "${TOPIC_ID}"
      batch_size => 16384  #logstash每次向ES传输的数据量大小,单位为字节
      codec => "${CODEC}" 
   } }

  if [type] == "app1-sidecar-access-log" {
    kafka {
      bootstrap_servers => "${KAFKA_SERVER}"
      topic_id => "${TOPIC_ID}"
      batch_size => 16384
      codec => "${CODEC}"
  }}
}

构建镜像

# vim build-commond.sh 
#!/bin/bash
nerdctl  build -t harbor.zhao.net/baseimages/logstash:v7.12.1-sidecar .
nerdctl push harbor.zhao.net/baseimages/logstash:v7.12.1-sidecar

# ./build-commond.sh

5.2.2 编写yaml文件

# vim 2.tomcat-app1.yaml 
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: web-tomcat-app1-deployment-label
  name: web-tomcat-app1-deployment #当前版本的deployment 名称
  namespace: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-tomcat-app1-selector
  template:
    metadata:
      labels:
        app: web-tomcat-app1-selector
    spec:
      containers:
      - name: sidecar-container
        image: harbor.zhao.net/baseimages/logstash:v7.12.1-sidecar    # sidcar镜像
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        env:
        - name: "KAFKA_SERVER"
          value: "172.20.20.25:9092,172.20.20.26:9092,172.20.20.27:9092"    # kafka集群地址
        - name: "TOPIC_ID"
          value: "tomcat-app1-topic"    # topic id
        - name: "CODEC"
          value: "json"    # json格式日志
        volumeMounts:
        - name: applogs
          mountPath: /var/log/applog
      - name: web-tomcat-app1-container
        image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/tomcat-app1:v1    # tomcat业务镜像
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
        volumeMounts:
        - name: applogs
          mountPath: /apps/tomcat/logs
        startupProbe:
          httpGet:
            path: /myapp/index.html
            port: 8080
          initialDelaySeconds: 5 #首次检测延迟5s
          failureThreshold: 3  #从成功转为失败的次数
          periodSeconds: 3 #探测间隔周期
        readinessProbe:
          httpGet:
            #path: /monitor/monitor.html
            path: /myapp/index.html
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
        livenessProbe:
          httpGet:
            #path: /monitor/monitor.html
            path: /myapp/index.html
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
      volumes:
      - name: applogs #定义通过emptyDir实现业务容器与sidecar容器的日志共享,以让sidecar收集业务容器中的日志
        emptyDir: {}

编写service yaml文件

# vim 3.tomcat-service.yaml 
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: web-tomcat-app1-service-label
  name: web-tomcat-app1-service
  namespace: web
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    nodePort: 40080
  selector:
    app: web-tomcat-app1-selector

验证

# kubectl get pod -n web
NAME                                          READY   STATUS      RESTARTS      AGE
web-tomcat-app1-deployment-7887d4c88d-2485b   2/2     Running     0             18m
web-tomcat-app1-deployment-7887d4c88d-5hlsg   2/2     Running     0             18m
web-tomcat-app1-deployment-7887d4c88d-dnrpl   2/2     Running     0             18m

# kubectl get svc -n web
NAME                      TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
web-tomcat-app1-service   NodePort   10.100.42.133    <none>        80:40080/TCP                 21d

访问测试


998aab0e728fa078bc8d1e142ed3a2a.png

5.2.3 验证kafka日志数据

1f938e9018f94bd429bbeecb274a872.png

5.2.4 配置Logstash服务器

root@logstash1:/etc/logstash/conf.d# vim sidecar-log-to-es.conf 
input {
  kafka {
    bootstrap_servers => "172.20.20.25:9092,172.20.20.26:9092,172.20.20.27:9092"
    topics => ["tomcat-app1-topic"]
    codec => "json"
  }
}

output {
  #if [fields][type] == "app1-access-log" {
  if [type] == "app1-sidecar-access-log" {
    elasticsearch {
      hosts => ["172.20.20.21:9200","172.20.20.22:9200","172.20.20.23:9200"]
      index => "sidecar-app1-accesslog-%{+YYYY.MM.dd}"
    }
  }

  #if [fields][type] == "app1-catalina-log" {
  if [type] == "app1-sidecar-catalina-log" {
    elasticsearch {
      hosts => ["172.20.20.21:9200","172.20.20.22:9200","172.20.20.23:9200"]
      index => "sidecar-app1-catalinalog-%{+YYYY.MM.dd}"
    }
  }
}

#重启服务
# systemctl restart logstash.service

5.2.5 验证Elasticsearch日志数据

image.png

5.2.6 Kibana展示日志

按照之前的步骤创建索引


494b582cdaddbc228d403fa111fcaaa.png

展示日志


image.png
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、Kubernetes Container、Pod、Namespace内存及CPU限制 Container CP...
    少年_c3dc阅读 754评论 0 0
  • 一、简介 Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上...
    小波同学阅读 7,784评论 0 1
  • 1.获取资源 kubectlget 2.查看资源详情 kubectl describe <reousrce_typ...
    365a3735241a阅读 4,502评论 0 0
  • 简述ETCD及其特点? etcd 是 CoreOS 团队发起的开源项目,是一个管理配置信息和服务发现(servic...
    成浅阅读 2,767评论 0 1
  • [toc] 一、HPA与弹性伸缩 1.1 scale scale命令可以使用命令行通过控制器调整副本数 1.2 H...
    Walker_7797阅读 5,743评论 0 0