구성 파일로 kubelet 매개변수 설정하기

구성 파일로 kubelet 매개변수 설정하기 (Set Kubelet Parameters Via A Configuration File)

출처: 문서

본문

시작하기 전에 (Before you begin)

이 페이지의 일부 단계는 jq 도구를 사용해요. jq가 없으면 운영체제의 소프트웨어 소스로 설치하거나 https://jqlang.github.io/jq/ 에서 가져올 수 있어요. 일부 단계는 curl 설치도 포함하는데, 운영체제의 소프트웨어 소스로 설치할 수 있어요.

kubelet의 구성 매개변수 중 일부는 명령줄 플래그 대신 디스크의 구성 파일로 설정할 수 있어요. 구성 파일로 매개변수를 제공하는 것은 노드 배포와 구성 관리를 단순화하므로 권장되는 접근 방식이에요.

구성 파일 만들기 (Create the config file)

파일로 구성할 수 있는 kubelet 구성의 부분집합은 KubeletConfiguration 구조체로 정의돼요. 구성 파일은 이 구조체의 매개변수를 나타내는 JSON 또는 YAML 표현이어야 해요. kubelet이 파일에 대한 읽기 권한이 있는지 확인하세요.

이 파일이 어떻게 보이는지의 예시는 다음과 같아요.

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: "192.168.0.8"
port: 20250
serializeImagePulls: false
evictionHard:
    memory.available:  "100Mi"
    nodefs.available:  "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"
    imagefs.inodesFree: "5%"

이 예시에서 kubelet은 다음 설정으로 구성돼요.

  • address: kubelet은 IP 주소 192.168.0.8에서 서빙해요.
  • port: kubelet은 포트 20250에서 서빙해요.
  • serializeImagePulls: 이미지 풀은 병렬로 수행돼요.
  • evictionHard: kubelet은 다음 조건 중 하나에서 Pod를 퇴거해요.
    • 노드의 사용 가능한 메모리가 100MiB 아래로 떨어질 때.
    • 노드의 메인 파일시스템의 사용 가능한 공간이 10% 미만일 때.
    • 이미지 파일시스템의 사용 가능한 공간이 15% 미만일 때.
    • 노드의 메인 파일시스템 inode의 95% 이상이 사용 중일 때.

참고: 예시에서 evictionHard에 대한 한 매개변수의 기본값만 변경하면, 다른 매개변수의 기본값은 상속되지 않고 0으로 설정돼요. 커스텀 값을 제공하려면 모든 임계값을 각각 제공해야 해요. 또는 kubelet 구성 파일에서 MergeDefaultEvictionSettings를 true로 설정하면, 어떤 매개변수가 변경되어도 다른 매개변수가 0 대신 기본값을 상속해요. imagefs는 컨테이너 런타임이 컨테이너 이미지와 컨테이너 쓰기 가능 레이어를 저장하는 데 사용하는 선택적 파일시스템이에요.

구성 파일로 구성된 kubelet 프로세스 시작하기 (Start a kubelet process configured via the config file)

참고: kubeadm으로 클러스터를 초기화한다면, kubeadm init으로 클러스터를 만들 때 kubelet-config를 사용하세요. 자세한 내용은 kubeadm으로 kubelet 구성하기를 참고하세요.

kubelet 구성 파일의 경로로 설정된 --config 플래그로 kubelet을 시작해요. 그러면 kubelet이 이 파일에서 구성을 로드해요. 구성 파일과 같은 값을 대상으로 하는 명령줄 플래그는 그 값을 재정의한다는 점에 주의하세요. 이는 명령줄 API와의 하위 호환성을 보장하는 데 도움을 줘요.

kubelet 구성 파일의 상대 파일 경로는 kubelet 구성 파일의 위치에 상대적으로 해석되는 반면, 명령줄 플래그의 상대 경로는 kubelet의 현재 작업 디렉터리에 상대적으로 해석된다는 점에 주의하세요.

일부 기본값은 명령줄 플래그와 kubelet 구성 파일 사이에서 다르다는 점에 주의하세요. --config가 제공되고 값이 명령줄로 지정되지 않으면 KubeletConfiguration 버전의 기본값이 적용돼요. 위 예시에서 이 버전은 kubelet.config.k8s.io/v1beta1이에요.

kubelet 구성 파일의 drop-in 디렉터리 (Drop-in directory for kubelet configuration files)

kubelet에 대한 drop-in 구성 디렉터리를 지정할 수 있어요. 기본적으로 kubelet은 어디에서도 drop-in 구성 파일을 찾지 않아요 — 경로를 지정해야 해요. 예: --config-dir=/etc/kubernetes/kubelet.conf.d

Kubernetes v1.28부터 v1.29의 경우, kubelet 프로세스에 환경 변수 KUBELET_CONFIG_DROPIN_DIR_ALPHA도 설정한 경우에만 --config-dir을 지정할 수 있어요(그 변수의 값은 상관없어요).

참고: 유효한 kubelet drop-in 구성 파일의 접미사는 .conf여야 해요. 예: 99-kubelet-address.conf

kubelet은 구성 drop-in 디렉터리의 파일을 전체 파일 이름을 알파벳순으로 정렬해 처리해요. 예를 들어 00-kubelet.conf가 먼저 처리되고 01-kubelet.conf라는 파일로 재정의돼요.

이 파일들은 부분 구성을 포함할 수 있지만 유효하지 않아서는 안 되며, 타입 메타데이터, 특히 apiVersionkind를 포함해야 해요. 검증은 kubelet 내부에 저장된 최종 결과 구성 구조에 대해서만 수행돼요. 이는 다른 소스의 kubelet 구성을 관리하고 병합하는 데 유연성을 제공하면서 바람직하지 않은 구성을 방지해요. 다만 구성 필드의 데이터 타입에 따라 동작이 달라진다는 점을 주의하는 것이 중요해요.

kubelet 구성 구조의 다른 데이터 타입은 다르게 병합돼요. 자세한 내용은 참조 문서를 참고하세요.

kubelet 구성 병합 순서 (Kubelet configuration merging order)

시작 시 kubelet은 다음에서 구성을 병합해요.

  • 명령줄에 지정된 기능 게이트(가장 낮은 우선순위)
  • kubelet 구성
  • 정렬 순서에 따른 drop-in 구성 파일
  • 기능 게이트를 제외한 명령줄 인자(가장 높은 우선순위)

참고: kubelet의 구성 drop-in 디렉터리 메커니즘은 kubeadm 도구가 구성을 패치할 수 있게 하는 방식과 비슷하지만 다르다. kubeadm 도구는 자체 구성에 특정 패치 전략을 사용하는 반면, kubelet 구성 drop-in 파일의 유일한 패치 전략은 replace다. kubelet은 접미사를 알파벳순으로 정렬하여 병합 순서를 결정하고, 더 높은 우선순위 파일에 있는 모든 필드를 교체한다.

kubelet 구성 보기 (Viewing the kubelet configuration)

이 기능으로 구성이 여러 파일에 걸쳐 펼쳐질 수 있으므로, 최종 적용된 구성을 검사하려면 다음 단계로 kubelet 구성을 검사할 수 있어요.

터미널에서 kubectl proxy로 프록시 서버를 시작해요.

kubectl proxy

다음과 같은 출력이 나와요.

Starting to serve on 127.0.0.1:8001

다른 터미널 창을 열고 curl로 kubelet 구성을 가져와요. <node-name>을 실제 노드 이름으로 교체하세요.

curl -X GET http://127.0.0.1:8001/api/v1/nodes/<node-name>/proxy/configz | jq .
{
  "kubeletconfig": {
    "enableServer": true,
    "staticPodPath": "/var/run/kubernetes/static-pods",
    "syncFrequency": "1m0s",
    "fileCheckFrequency": "20s",
    "httpCheckFrequency": "20s",
    "address": "192.168.1.16",
    "port": 10250,
    "readOnlyPort": 10255,
    "tlsCertFile": "/var/lib/kubelet/pki/kubelet.crt",
    "tlsPrivateKeyFile": "/var/lib/kubelet/pki/kubelet.key",
    "rotateCertificates": true,
    "authentication": {
      "x509": {
        "clientCAFile": "/var/run/kubernetes/client-ca.crt"
      },
      "webhook": {
        "enabled": true,
        "cacheTTL": "2m0s"
      },
      "anonymous": {
        "enabled": true
      }
    },
    "authorization": {
      "mode": "AlwaysAllow",
      "webhook": {
        "cacheAuthorizedTTL": "5m0s",
        "cacheUnauthorizedTTL": "30s"
      }
    },
    "registryPullQPS": 5,
    "registryBurst": 10,
    "eventRecordQPS": 50,
    "eventBurst": 100,
    "enableDebuggingHandlers": true,
    "healthzPort": 10248,
    "healthzBindAddress": "127.0.0.1",
    "oomScoreAdj": -999,
    "clusterDomain": "cluster.local",
    "clusterDNS": [
      "10.0.0.10"
    ],
    "streamingConnectionIdleTimeout": "4h0m0s",
    "nodeStatusUpdateFrequency": "10s",
    "nodeStatusReportFrequency": "5m0s",
    "nodeLeaseDurationSeconds": 40,
    "imageMinimumGCAge": "2m0s",
    "imageMaximumGCAge": "0s",
    "imageGCHighThresholdPercent": 85,
    "imageGCLowThresholdPercent": 80,
    "volumeStatsAggPeriod": "1m0s",
    "cgroupsPerQOS": true,
    "cgroupDriver": "systemd",
    "cpuManagerPolicy": "none",
    "cpuManagerReconcilePeriod": "10s",
    "memoryManagerPolicy": "None",
    "topologyManagerPolicy": "none",
    "topologyManagerScope": "container",
    "runtimeRequestTimeout": "2m0s",
    "hairpinMode": "promiscuous-bridge",
    "maxPods": 110,
    "podPidsLimit": -1,
    "resolvConf": "/run/systemd/resolve/resolv.conf",
    "cpuCFSQuota": true,
    "cpuCFSQuotaPeriod": "100ms",
    "nodeStatusMaxImages": 50,
    "maxOpenFiles": 1000000,
    "contentType": "application/vnd.kubernetes.protobuf",
    "kubeAPIQPS": 50,
    "kubeAPIBurst": 100,
    "serializeImagePulls": true,
    "evictionHard": {
      "imagefs.available": "15%",
      "memory.available": "100Mi",
      "nodefs.available": "10%",
      "nodefs.inodesFree": "5%",
      "imagefs.inodesFree": "5%"
    },
    "evictionPressureTransitionPeriod": "1m0s",
    "mergeDefaultEvictionSettings": false,
    "enableControllerAttachDetach": true,
    "makeIPTablesUtilChains": true,
    "iptablesMasqueradeBit": 14,
    "iptablesDropBit": 15,
    "featureGates": {
      "AllAlpha": false
    },
    "failSwapOn": false,
    "memorySwap": {},
    "containerLogMaxSize": "10Mi",
    "containerLogMaxFiles": 5,
    "configMapAndSecretChangeDetectionStrategy": "Watch",
    "enforceNodeAllocatable": [
      "pods"
    ],
    "volumePluginDir": "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/",
    "logging": {
      "format": "text",
      "flushFrequency": "5s",
      "verbosity": 3,
      "options": {
        "json": {
          "infoBufferSize": "0"
        }
      }
    },
    "enableSystemLogHandler": true,
    "enableSystemLogQuery": false,
    "shutdownGracePeriod": "0s",
    "shutdownGracePeriodCriticalPods": "0s",
    "enableProfilingHandler": true,
    "enableDebugFlagsHandler": true,
    "seccompDefault": false,
    "registerNode": true,
    "localStorageCapacityIsolation": true,
    "containerRuntimeEndpoint": "unix:///var/run/crio/crio.sock"
  }
}

다음 단계 (What's next)

  • KubeletConfiguration 참조를 확인해 kubelet 구성에 대해 더 배우기
  • 참조 문서에서 kubelet 구성 병합에 대해 더 배우기

더 알아보기 (Learn more)