Red Hat CoreOS 작업자 노드의 성능 튜닝

Satellite

지원되는 작업자 노드 운영 체제
Red Hat CoreOS (RHCOS)

Red Hat CoreOS 작업자 노드 성능을 조정하려면 CPU 고정, NUMA(비균일 메모리 액세스) 및 대용량 페이지를 활성화할 수 있습니다. 이러한 구성은 엄격한 성능 요구 사항이 있는 애플리케이션에 도움이 될 수 있습니다. 그러나 이러한 사용자 지정으로 인해 워크로드 스케줄링 문제가 발생할 수 있습니다.

Red Hat OpenShift 에서 MachineConfig 파일로 워커 노드 성능을 조정하는 대신 daemonset 파일로 호스트를 수정할 수 있습니다. 자세한 내용은 Calico MTU 변경하기 또는 Red Hat CoreOS 워커 노드 성능 튜닝하기를 참조하세요.

Node 기능 감지 운영자 배치

Satellite

작업자 노드에서 NUMA, CPU 고정 및 대용량 페이지를 사용으로 설정하기 전에 Node Feature Discovery Operator를 배치해야 합니다. 자세한 내용은 Node 기능 검색 연산자를 참조하세요.

작업자 노드에서 NUMA (Non-Uniform Memory Access), CPU 고정 및 대용량 페이지 사용

Satellite

시작하기 전에 Node Feature Discovery Operator 를 배치했는지 확인하십시오.

  1. 다음 DaemonSetcustomize.yaml 파일에 저장하십시오.

    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: ibm-user-custom-configurator-privileged
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:openshift:scc:privileged
    subjects:
      - kind: ServiceAccount
        name: ibm-user-custom-configurator
        namespace: kube-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    data:
      89-hugepages.conf: |
        vm.nr_hugepages=<<NUMBER_OF_HUGEPAGES>>
      configure.sh: |
        #!/usr/bin/env bash
        set -x
        cp -f /scripts/ibm-user-custom-configuration.sh /host-usr-local-bin/ibm-user-custom-configuration.sh
        chmod 0755 /host-usr-local-bin/ibm-user-custom-configuration.sh
        cp -f /scripts/ibm-user-custom-configuration.service /host-etc-systemd-dir/ibm-user-custom-configuration.service
        chmod 0644 /host-etc-systemd-dir/ibm-user-custom-configuration.service
        if [[ -f /scripts/89-hugepages.conf ]]; then
          cp -f /scripts/89-hugepages.conf /host-etc-systctld-dir/89-hugepages.conf
        fi
        nsenter -t 1 -m -u -i -n -p -- systemctl daemon-reload
        nsenter -t 1 -m -u -i -n -p -- systemctl enable ibm-user-custom-configuration.service
        nsenter -t 1 -m -u -i -n -p -- systemctl start ibm-user-custom-configuration.service
      ibm-user-custom-configuration.sh: |
        #!/usr/bin/env bash
        set -x
        GIGABYTES_RESERVED_MEMORY=$(echo $SYSTEM_RESERVED_MEMORY | awk -F 'Gi' '{print $1}')
        GIGABYTES_RESERVED_MEMORY_ROUNDED_UP=$(echo $GIGABYTES_RESERVED_MEMORY | awk '{print int($1+0.999)}')
        sed -i "s/SYSTEM_RESERVED_MEMORY=.*/SYSTEM_RESERVED_MEMORY=${GIGABYTES_RESERVED_MEMORY_ROUNDED_UP}Gi/g" /etc/node-sizing.env
        TOTAL_NUMA_MEMORY_TO_ALLOCATE=$(echo "$GIGABYTES_RESERVED_MEMORY_ROUNDED_UP" "1024" | awk '{print $1 * $2 + 100}')
        if cat /etc/kubernetes/kubelet.conf | jq -r .; then
          cat >/tmp/ibm-user-config.conf.json <<EOF
          {
            "topologyManagerPolicy": "<<TOPOLOGY_MANAGER_POLICY_VALUE>>",
            "memoryManagerPolicy": "Static",
            "cpuManagerPolicy": "static",
            "reservedMemory": [
              {
                "numaNode": 0,
                "limits": {
                "memory": "${TOTAL_NUMA_MEMORY_TO_ALLOCATE}Mi"
                  }
              }
            ]
          }
        EOF
          if ! cat /tmp/ibm-user-config.conf.json | jq -r .; then
            exit 1
          fi
          if ! jq -s '.[0] * .[1]' /tmp/ibm-user-config.conf.json /etc/kubernetes/kubelet.conf > /etc/kubernetes/tmp-kubelet.conf; then
            exit 1
          fi
          mv -f /etc/kubernetes/tmp-kubelet.conf /etc/kubernetes/kubelet.conf
          else
            cat >/tmp/ibm-user-config.conf <<EOF
        #START USER CONFIG
        topologyManagerPolicy: <<TOPOLOGY_MANAGER_POLICY_VALUE>>
        memoryManagerPolicy: Static
        cpuManagerPolicy: static
        reservedMemory:
          - numaNode: 0
            limits:
              memory: ${TOTAL_NUMA_MEMORY_TO_ALLOCATE}Mi
        #END USER CONFIG
        EOF
          sed -i '/#START USER CONFIG/,/#END USER CONFIG/d' /etc/kubernetes/kubelet.conf
          cat /tmp/ibm-user-config.conf >>/etc/kubernetes/kubelet.conf
        fi
      ibm-user-custom-configuration.service: |
        [Unit]
        Description=Add custom user config to kubelet
        Before=kubelet.service
        After=kubelet-auto-node-size.service
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        EnvironmentFile=/etc/node-sizing.env
        ExecStart=/usr/local/bin/ibm-user-custom-configuration.sh
        [Install]
        WantedBy=multi-user.target
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        app: ibm-user-custom-configurator
      name: ibm-user-custom-configurator
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          app: ibm-user-custom-configurator
      template:
        metadata:
          labels:
            app: ibm-user-custom-configurator
        spec:
          nodeSelector:
            feature.node.kubernetes.io/memory-numa: "true"
            ibm-cloud.kubernetes.io/os: RHCOS
          tolerations:
            - operator: "Exists"
          hostPID: true
          serviceAccount: ibm-user-custom-configurator
          initContainers:
            - name: configure
              image: "registry.access.redhat.com/ubi8/ubi:8.6"
              command: ['/bin/bash', '-c', 'mkdir /cache && cp /scripts/configure.sh /cache && chmod +x /cache/configure.sh && /bin/bash /cache/configure.sh']
              securityContext:
                privileged: true
              volumeMounts:
                - mountPath: /scripts
                  name: script-config
                - mountPath: /host-etc-systemd-dir
                  name: etc-systemd-dir
                - mountPath: /host-usr-local-bin
                  name: usr-local-bin
                - mountPath: /host-etc-systctld-dir
                  name: etc-systctld-dir
          containers:
            - name: pause
              image: us.icr.io/armada-master/pause:3.2
          volumes:
            - name: etc-systemd-dir
              hostPath:
                path: /etc/systemd/system
            - name: etc-systctld-dir
              hostPath:
                path: /etc/sysctl.d
            - name: usr-local-bin
              hostPath:
                path: /usr/local/bin
            - name: script-config
              configMap:
                name: ibm-user-custom-configurator
    
  2. DaemonSet 값을 편집하여 성능을 조정하십시오.

NUMBER_OF_HUGEPAGES

할당할 대형 페이지 수를 입력하십시오. 예를 들어, 2048 입니다. 대형 페이지를 사용하지 않으려면 0 를 입력하십시오. 대형 페이지를 많이 할당할수록 애플리케이션에 사용할 수 있는 전체 메모리가 줄어듭니다.

TOPOLOGY_MANAGER_POLICY_VALUE

사용하려는 토폴로지 관리자 정책을 입력합니다. best-effort 정책은 최대한의 예약 가용성을 보장하기 위해 권장됩니다. 그러나 다른 정책을 사용하여 워크로드 스케줄링 가용성을 줄이면서 더 엄격한 요구 사항 검증을 수행할 수 있습니다. 자세한 내용은 토폴로지 관리자를 참조하세요.

nodeSelector 섹션을 편집하여 작업자 노드의 서브세트에만 구성을 적용할 수 있습니다.

  1. 다음 명령을 실행하여 DaemonSet 를 적용하십시오.
    kubectl replace --force -f customize.yaml
    
  2. 팟 (Pod) 이 Running 상태가 되었는지 확인하십시오.
    kubectl get pods -n kube-system -l app=ibm-user-custom-configurator -o wide
    
  3. 팟 (Pod) 이 실행되면 각 작업자 노드를 다시 부팅하십시오.
    1. 워커 노드에 디버그 포드를 배포하세요.
        oc debug node/NODE_NAME
        ```
    1. 디버그 세션이 시작된 후 다음 명령을 실행하십시오.
    ```sh {: pre}
        nsenter -t 1 -m -u -i -n -p -- reboot
        ```
    1. 재부팅하려는 각 워커 노드에 대해 이 단계를 반복하십시오.
    
    
    

작업자 노드에서 CPU 고정 및 대용량 페이지 사용

Satellite

시작하기 전에 Node Feature Discovery Operator 를 배치했는지 확인하십시오.

  1. 다음 DaemonSetcpu-pinning.yaml 파일에 저장하십시오.

    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: ibm-user-custom-configurator-privileged
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:openshift:scc:privileged
    subjects:
      - kind: ServiceAccount
        name: ibm-user-custom-configurator
        namespace: kube-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    data:
      89-hugepages.conf: |
        vm.nr_hugepages=<<NUMBER_OF_HUGEPAGES>>
      configure.sh: |
        #!/usr/bin/env bash
        set -x
        cp -f /scripts/ibm-user-custom-configuration.sh /host-usr-local-bin/ibm-user-custom-configuration.sh
        chmod 0755 /host-usr-local-bin/ibm-user-custom-configuration.sh
        cp -f /scripts/ibm-user-custom-configuration.service /host-etc-systemd-dir/ibm-user-custom-configuration.service
        chmod 0644 /host-etc-systemd-dir/ibm-user-custom-configuration.service
        if [[ -f /scripts/89-hugepages.conf ]]; then
          cp -f /scripts/89-hugepages.conf /host-etc-systctld-dir/89-hugepages.conf
        fi
        nsenter -t 1 -m -u -i -n -p -- systemctl daemon-reload
        nsenter -t 1 -m -u -i -n -p -- systemctl enable ibm-user-custom-configuration.service
        nsenter -t 1 -m -u -i -n -p -- systemctl start ibm-user-custom-configuration.service
      ibm-user-custom-configuration.sh: |
        #!/usr/bin/env bash
        set -x
        if cat /etc/kubernetes/kubelet.conf | jq -r .; then
          cat >/tmp/ibm-user-config.conf.json <<EOF
          {
            "cpuManagerPolicy": "static"
          }
        EOF
          if ! cat /tmp/ibm-user-config.conf.json | jq -r .; then
            exit 1
          fi
          if ! jq -s '.[0] * .[1]' /tmp/ibm-user-config.conf.json /etc/kubernetes/kubelet.conf > /etc/kubernetes/tmp-kubelet.conf; then
            exit 1
          fi
          mv -f /etc/kubernetes/tmp-kubelet.conf /etc/kubernetes/kubelet.conf
        else
          cat >/tmp/ibm-user-config.conf <<EOF
        #START USER CONFIG
        cpuManagerPolicy: static
        #END USER CONFIG
        EOF
          sed -i '/#START USER CONFIG/,/#END USER CONFIG/d' /etc/kubernetes/kubelet.conf
          cat /tmp/ibm-user-config.conf >>/etc/kubernetes/kubelet.conf
        fi
      ibm-user-custom-configuration.service: |
        [Unit]
        Description=Add custom user config to kubelet
        Before=kubelet.service
        After=kubelet-auto-node-size.service
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        EnvironmentFile=/etc/node-sizing.env
        ExecStart=/usr/local/bin/ibm-user-custom-configuration.sh    
        [Install]
        WantedBy=multi-user.target
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        app: ibm-user-custom-configurator
      name: ibm-user-custom-configurator
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          app: ibm-user-custom-configurator
      template:
        metadata:
          labels:
            app: ibm-user-custom-configurator
        spec:
          nodeSelector:
            ibm-cloud.kubernetes.io/os: RHCOS
          tolerations:
            - operator: "Exists"
          hostPID: true
          serviceAccount: ibm-user-custom-configurator
          initContainers:
            - name: configure
              image: "registry.access.redhat.com/ubi8/ubi:8.6"
              command: ['/bin/bash', '-c', 'mkdir /cache && cp /scripts/configure.sh /cache && chmod +x /cache/configure.sh && /bin/bash /cache/configure.sh']
              securityContext:
                privileged: true
              volumeMounts:
                - mountPath: /scripts
                  name: script-config
                - mountPath: /host-etc-systemd-dir
                  name: etc-systemd-dir
                - mountPath: /host-usr-local-bin
                  name: usr-local-bin
                - mountPath: /host-etc-systctld-dir
                  name: etc-systctld-dir
          containers:
            - name: pause
              image: us.icr.io/armada-master/pause:3.2
          volumes:
            - name: etc-systemd-dir
              hostPath:
                path: /etc/systemd/system
            - name: etc-systctld-dir
              hostPath:
                path: /etc/sysctl.d
            - name: usr-local-bin
              hostPath:
                path: /usr/local/bin
            - name: script-config
              configMap:
                name: ibm-user-custom-configurator
    
  2. DaemonSet 값을 편집하여 성능을 조정하십시오.

NUMBER_OF_HUGEPAGES

할당할 대형 페이지 수를 입력하십시오. 예를 들어, 2048 입니다. 대형 페이지를 사용하지 않으려면 0 를 입력하십시오. 대형 페이지를 많이 할당할수록 애플리케이션에 사용할 수 있는 전체 메모리가 줄어듭니다.

nodeSelector 섹션을 편집하여 작업자 노드의 서브세트에만 구성을 적용할 수 있습니다.

  1. 다음 명령을 실행하여 DaemonSet 를 적용하십시오.
    kubectl replace --force -f cpu-pinnning.yaml
    
  2. 팟 (Pod) 이 Running 상태가 되었는지 확인하십시오.
    kubectl get pods -n kube-system -l app=ibm-user-custom-configurator -o wide
    
  3. 팟 (Pod) 이 실행되면 각 작업자 노드를 다시 부팅하십시오.
    1. 워커 노드에 디버그 포드를 배포하세요.
        oc debug node/NODE_NAME
        ```
    1. 디버그 세션이 시작된 후 다음 명령을 실행하십시오.
    ```sh {: pre}
        nsenter -t 1 -m -u -i -n -p -- reboot
        ```
    1. 재부팅하려는 각 워커 노드에 대해 이 단계를 반복하십시오.
    
    

kernel-devel 패키지 사용

Satellite

Satellite 서비스 또는 스토리지 (예: Spectrum Scale Fusion) 를 사용하려면 kernel-devel 패키지를 사용으로 설정해야 합니다.

사용자 정의 구성 맵 및 머신 구성을 작업자 노드에 적용하여 kernel-devel 를 사용으로 설정하려면 다음 단계를 완료하십시오.

  1. MachineConfig 를 적용하려면 다음 명령을 실행하십시오.

    ibmcloud ks cluster config --cluster CLUSTERID
    cat >"/tmp/kernel-devel-payload.yaml" <<EOF
    apiVersion: v1
    kind: List
    metadata:
      name: pvg-machine-config-tester
      annotations:
    items:
      - apiVersion: v1
        kind: Namespace
        metadata:
          name: ibm-machine-config
      - apiVersion: v1
        data:
          config: |+
            apiVersion: machineconfiguration.openshift.io/v1
            kind: MachineConfig
            metadata:
              name: 97-kerneldevel
              labels:
                machineconfiguration.openshift.io/role: worker
            spec:
              config:
                ignition:
                  version: 3.2.0
              extensions:
              - kernel-devel
        kind: ConfigMap
        metadata:
          labels:
            ibm-cloud.kubernetes.io/user-specified-config: "true"
          name: user-ignition-config-97-kerneldevel
          namespace: ibm-machine-config
    EOF
    kubectl apply -f /tmp/kernel-devel-payload.yaml
    
  2. 리소스가 배포될 때까지 기다리세요. 이 작업은 5분이상 소요될 수 있습니다.

  3. 구성 맵의 세부사항을 검토하여 배치가 성공했는지 확인하십시오.

    1. config-validation="valid" 필드가 있는지 확인하십시오.
        kubectl get cm -n ibm-machine-config user-ignition-config-97-kerneldevel -o yaml | grep config-validation
        ```
    1. `user-ignition-config-97-kerneldevel` 가 구성 맵에 있는지 확인하십시오.
    ```sh {: pre}
        kubectl get cm -n ibm-machine-config -l ibm-cloud.kubernetes.io/nodepoolfeedback="true" -o yaml | grep user-ignition-config-97-kerneldevel
        ```
    
  4. 클러스터에 워커 노드를 추가하세요. 추가하는 작업자 노드에는 kernel-devel 가 사용으로 설정되어 있습니다.

  5. kernel-devel 가 활성화되어 있는지 확인하십시오.

    1. 노드 중 하나에서 디버그 팟 (Pod) 을 시작하십시오.
        oc debug node/NODEIP
        ```
    1. 다음 `nsenter` 명령을 실행하십시오.
    ```sh {: pre}
        nsenter -t 1 -m -u -i -n -p -- rpm -qa | grep kernel-devel
        ```
    
  6. 선택사항: kernel-devel 가 더 이상 필요하지 않은 경우 다음 명령을 실행하여 제거할 수 있습니다.

    kubectl delete cm -n ibm-machine-config user-ignition-config-97-kerneldevel
    

성능 사용자 정의 제거

Satellite

작업자 노드에서 사용자 정의를 제거하고 기본 구성으로 재설정하려면 다음 DaemonSet 을 적용하십시오.

  1. 다음 DaemonSetremove-custom.yaml 파일에 저장하십시오.

    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: ibm-user-custom-configurator-privileged
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:openshift:scc:privileged
    subjects:
      - kind: ServiceAccount
        name: ibm-user-custom-configurator
        namespace: kube-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ibm-user-custom-configurator
      namespace: kube-system
    data:
      89-hugepages.conf: |
        vm.nr_hugepages=0
      configure.sh: |
        #!/usr/bin/env bash
        set -x
        cp -f /scripts/ibm-user-custom-configuration.sh /host-usr-local-bin/ibm-user-custom-configuration.sh
        chmod 0755 /host-usr-local-bin/ibm-user-custom-configuration.sh
        cp -f /scripts/ibm-user-custom-configuration.service /host-etc-systemd-dir/ibm-user-custom-configuration.service
        chmod 0644 /host-etc-systemd-dir/ibm-user-custom-configuration.service
        if [[ -f /scripts/89-hugepages.conf ]]; then
          cp -f /scripts/89-hugepages.conf /host-etc-systctld-dir/89-hugepages.conf
        fi
        nsenter -t 1 -m -u -i -n -p -- systemctl daemon-reload
        nsenter -t 1 -m -u -i -n -p -- systemctl enable ibm-user-custom-configuration.service
        nsenter -t 1 -m -u -i -n -p -- systemctl start ibm-user-custom-configuration.service
      ibm-user-custom-configuration.sh: |
        #!/usr/bin/env bash
        set -x
        if cat /etc/kubernetes/kubelet.conf | jq -r .; then
          if ! jq 'del(.topologyManagerPolicy, .memoryManagerPolicy, .cpuManagerPolicy, .reservedMemory)' /etc/kubernetes/kubelet.conf > /etc/kubernetes/tmp-kubelet.conf; then
            exit 1
          fi
          mv -f /etc/kubernetes/tmp-kubelet.conf /etc/kubernetes/kubelet.conf
        else
          sed -i '/#START USER CONFIG/,/#END USER CONFIG/d' /etc/kubernetes/kubelet.conf
        fi
      ibm-user-custom-configuration.service: |
        [Unit]
        Description=Add custom user config to kubelet
        Before=kubelet.service
        After=kubelet-auto-node-size.service
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        EnvironmentFile=/etc/node-sizing.env
        ExecStart=/usr/local/bin/ibm-user-custom-configuration.sh
        [Install]
        WantedBy=multi-user.target
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        app: ibm-user-custom-configurator
      name: ibm-user-custom-configurator
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          app: ibm-user-custom-configurator
      template:
        metadata:
          labels:
            app: ibm-user-custom-configurator
        spec:
          nodeSelector:
            ibm-cloud.kubernetes.io/os: RHCOS
          tolerations:
            - operator: "Exists"
          hostPID: true
          serviceAccount: ibm-user-custom-configurator
          initContainers:
            - name: configure
              image: "registry.access.redhat.com/ubi8/ubi:8.6"
              command: ['/bin/bash', '-c', 'mkdir /cache && cp /scripts/configure.sh /cache && chmod +x /cache/configure.sh && /bin/bash /cache/configure.sh']
              securityContext:
                privileged: true
              volumeMounts:
                - mountPath: /scripts
                  name: script-config
                - mountPath: /host-etc-systemd-dir
                  name: etc-systemd-dir
                - mountPath: /host-usr-local-bin
                  name: usr-local-bin
                - mountPath: /host-etc-systctld-dir
                  name: etc-systctld-dir
          containers:
            - name: pause
              image: us.icr.io/armada-master/pause:3.2
          volumes:
            - name: etc-systemd-dir
              hostPath:
                path: /etc/systemd/system
            - name: etc-systctld-dir
              hostPath:
                path: /etc/sysctl.d
            - name: usr-local-bin
              hostPath:
                path: /usr/local/bin
            - name: script-config
              configMap:
                name: ibm-user-custom-configurator
    
  2. 다음 명령을 실행하여 클러스터에 ‘ DaemonSet ’를 적용하십시오.

    kubectl replace --force -f remove-custom.yaml
    
  3. 팟 (Pod) 이 Running 상태가 되었는지 확인하십시오.

    kubectl get pods -n kube-system -l app=ibm-user-custom-configurator -o wide
    
  4. 팟 (Pod) 이 실행되면 각 작업자 노드를 다시 부팅하십시오.

    1. 워커 노드에 디버그 포드를 배포하세요.
        oc debug node/NODE_NAME
        ```
    1. 디버그 세션이 시작된 후 다음 명령을 실행하십시오.
    ```sh {: pre}
        nsenter -t 1 -m -u -i -n -p -- reboot
        ```
    1. 재부팅하려는 각 워커 노드에 대해 이 단계를 반복하십시오.