때때로 디버깅할 때 노드의 상태를 확인하는 것이 유용할 수 있다(예를 들어, 어떤 노드에서 실행되는 파드가 이상하게 행동하는 것을 발견했거나, 특정 노드에 파드가 스케줄링되지 않는 이유를 알아보기 위해). 파드의 경우와 마찬가지로, kubectl describe node 및 kubectl get node -o yaml 명령을 사용하여 노드에 대한 상세 정보를 볼 수 있다. 예를 들어, 노드가 다운 상태(네트워크 연결이 끊어졌거나, kubelet이 종료된 후 재시작되지 못했거나 등)라면 아래와 같은 출력이 나올 것이다. 노드가 NotReady 상태라는 것을 나타내는 이벤트(event)와, 더 이상 실행 중이 아닌 파드(NotReady 상태 이후 5분 뒤에 축출되었음)에 주목한다.
kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-worker-1 NotReady <none> 1h v1.23.3
kubernetes-node-bols Ready <none> 1h v1.23.3
kubernetes-node-st6x Ready <none> 1h v1.23.3
kubernetes-node-unaj Ready <none> 1h v1.23.3
kubectl describe node kube-worker-1
Name: kube-worker-1
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=kube-worker-1
kubernetes.io/os=linux
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 17 Feb 2022 16:46:30 -0500
Taints: node.kubernetes.io/unreachable:NoExecute
node.kubernetes.io/unreachable:NoSchedule
Unschedulable: false
Lease:
HolderIdentity: kube-worker-1
AcquireTime: <unset>
RenewTime: Thu, 17 Feb 2022 17:13:09 -0500
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
NetworkUnavailable False Thu, 17 Feb 2022 17:09:13 -0500 Thu, 17 Feb 2022 17:09:13 -0500 WeaveIsUp Weave pod has set this
MemoryPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
DiskPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
PIDPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
Ready Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
Addresses:
InternalIP: 192.168.0.113
Hostname: kube-worker-1
Capacity:
cpu: 2
ephemeral-storage: 15372232Ki
hugepages-2Mi: 0
memory: 2025188Ki
pods: 110
Allocatable:
cpu: 2
ephemeral-storage: 14167048988
hugepages-2Mi: 0
memory: 1922788Ki
pods: 110
System Info:
Machine ID: 9384e2927f544209b5d7b67474bbf92b
System UUID: aa829ca9-73d7-064d-9019-df07404ad448
Boot ID: 5a295a03-aaca-4340-af20-1327fa5dab5c
Kernel Version: 5.13.0-28-generic
OS Image: Ubuntu 21.10
Operating System: linux
Architecture: amd64
Container Runtime Version: containerd://1.5.9
Kubelet Version: v1.23.3
Kube-Proxy Version: v1.23.3
Non-terminated Pods: (4 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
default nginx-deployment-67d4bdd6f5-cx2nz 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
default nginx-deployment-67d4bdd6f5-w6kd7 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
kube-system kube-proxy-dnxbz 0 (0%) 0 (0%) 0 (0%) 0 (0%) 28m
kube-system weave-net-gjxxp 100m (5%) 0 (0%) 200Mi (10%) 0 (0%) 28m
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 1100m (55%) 1 (50%)
memory 456Mi (24%) 256Mi (13%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Events:
...
kubectl get node kube-worker-1 -o yaml
apiVersion:v1kind:Nodemetadata:annotations:kubeadm.alpha.kubernetes.io/cri-socket:/run/containerd/containerd.socknode.alpha.kubernetes.io/ttl:"0"volumes.kubernetes.io/controller-managed-attach-detach:"true"creationTimestamp:"2022-02-17T21:46:30Z"labels:beta.kubernetes.io/arch:amd64beta.kubernetes.io/os:linuxkubernetes.io/arch:amd64kubernetes.io/hostname:kube-worker-1kubernetes.io/os:linuxname:kube-worker-1resourceVersion:"4026"uid:98efe7cb-2978-4a0b-842a-1a7bf12c05f8spec:{}status:addresses:- address:192.168.0.113type:InternalIP- address:kube-worker-1type:Hostnameallocatable:cpu:"2"ephemeral-storage:"14167048988"hugepages-2Mi:"0"memory:1922788Kipods:"110"capacity:cpu:"2"ephemeral-storage:15372232Kihugepages-2Mi:"0"memory:2025188Kipods:"110"conditions:- lastHeartbeatTime:"2022-02-17T22:20:32Z"lastTransitionTime:"2022-02-17T22:20:32Z"message:Weave pod has set thisreason:WeaveIsUpstatus:"False"type:NetworkUnavailable- lastHeartbeatTime:"2022-02-17T22:20:15Z"lastTransitionTime:"2022-02-17T22:13:25Z"message:kubelet has sufficient memory availablereason:KubeletHasSufficientMemorystatus:"False"type:MemoryPressure- lastHeartbeatTime:"2022-02-17T22:20:15Z"lastTransitionTime:"2022-02-17T22:13:25Z"message:kubelet has no disk pressurereason:KubeletHasNoDiskPressurestatus:"False"type:DiskPressure- lastHeartbeatTime:"2022-02-17T22:20:15Z"lastTransitionTime:"2022-02-17T22:13:25Z"message:kubelet has sufficient PID availablereason:KubeletHasSufficientPIDstatus:"False"type:PIDPressure- lastHeartbeatTime:"2022-02-17T22:20:15Z"lastTransitionTime:"2022-02-17T22:15:15Z"message:kubelet is posting ready status. AppArmor enabledreason:KubeletReadystatus:"True"type:ReadydaemonEndpoints:kubeletEndpoint:Port:10250nodeInfo:architecture:amd64bootID:22333234-7a6b-44d4-9ce1-67e31dc7e369containerRuntimeVersion:containerd://1.5.9kernelVersion:5.13.0-28-generickubeProxyVersion:v1.23.3kubeletVersion:v1.23.3machineID:9384e2927f544209b5d7b67474bbf92boperatingSystem:linuxosImage:Ubuntu 21.10systemUUID:aa829ca9-73d7-064d-9019-df07404ad448
로그 보기
현재로서는 클러스터를 더 깊이 파고들려면 관련 머신에서 로그 확인이 필요하다. 관련 로그 파일
위치는 다음과 같다. (systemd 기반 시스템에서는 journalctl을 대신 사용해야 할 수도 있다.)
컨트롤 플레인 노드
/var/log/kube-apiserver.log - API 서버, API 제공을 담당
/var/log/kube-scheduler.log - 스케줄러, 스케줄 결정을 담당
/var/log/kube-controller-manager.log - 레플리케이션 컨트롤러를 담당하는 컨트롤러
워커 노드
/var/log/kubelet.log - Kubelet, 노드에서 컨테이너 실행을 담당
/var/log/kube-proxy.log - Kube Proxy, 서비스 로드밸런싱을 담당
클러스터 장애 모드
아래에 일부 오류 상황 예시 및 문제를 완화하기 위해 클러스터 설정을 조정하는 방법을 나열한다.
근본 원인
VM(들) 종료
클러스터 내 또는 클러스터와 사용자 간의 네트워크 분할
쿠버네티스 소프트웨어의 충돌
데이터 손실 또는 퍼시스턴트 스토리지 사용 불가 (e.g. GCE PD 또는 AWS EBS 볼륨)
운영자 오류, 예를 들면 잘못 구성된 쿠버네티스 소프트웨어 또는 애플리케이션 소프트웨어
특정 시나리오
API 서버 VM 종료 또는 API 서버 충돌
다음의 현상을 유발함
새로운 파드, 서비스, 레플리케이션 컨트롤러를 중지, 업데이트 또는 시작할 수 없다.
쿠버네티스 API에 의존하지 않는 기존 파드 및 서비스는 계속 정상적으로 작동할 것이다.
API 서버 백업 스토리지 손실
다음의 현상을 유발함
API 서버가 구동되지 않을 것이다.
kubelet에 도달할 수 없게 되지만, kubelet이 여전히 동일한 파드를 계속 실행하고 동일한 서비스 프록시를 제공할 것이다.
API 서버를 재시작하기 전에, 수동으로 복구하거나 API서버 상태를 재생성해야 한다.
지원 서비스 (노드 컨트롤러, 레플리케이션 컨트롤러 매니저, 스케쥴러 등) VM 종료 또는 충돌
현재 그것들은 API 서버와 같은 위치에 있기 때문에 API 서버와 비슷한 상황을 겪을 것이다.
미래에는 이들도 복제본을 가질 것이며 API서버와 별도로 배치될 수도 있다.
지원 서비스들은 상태(persistent state)를 자체적으로 유지하지는 않는다.
개별 노드 (VM 또는 물리적 머신) 종료
다음의 현상을 유발함
해당 노드의 파드가 실행을 중지
네트워크 분할
다음의 현상을 유발함
파티션 A는 파티션 B의 노드가 다운되었다고 생각한다. 파티션 B는 API 서버가 다운되었다고 생각한다. (마스터 VM이 파티션 A에 있다고 가정)
Kubelet 소프트웨어 오류
다음의 현상을 유발함
충돌한 kubelet은 노드에서 새 파드를 시작할 수 없다.
kubelet이 파드를 삭제할 수도 있고 삭제하지 않을 수도 있다.
노드는 비정상으로 표시된다.
레플리케이션 컨트롤러는 다른 곳에서 새 파드를 시작한다.
클러스터 운영자 오류
다음의 현상을 유발함
파드, 서비스 등의 손실
API 서버 백업 저장소 분실
API를 읽을 수 없는 사용자
기타
완화
조치: IaaS VM을 위한 IaaS 공급자의 자동 VM 다시 시작 기능을 사용한다.
다음을 완화할 수 있음: API 서버 VM 종료 또는 API 서버 충돌
다음을 완화할 수 있음: 지원 서비스 VM 종료 또는 충돌
조치: API 서버+etcd가 있는 VM에 IaaS 제공자의 안정적인 스토리지(예: GCE PD 또는 AWS EBS 볼륨)를 사용한다.
쿠버네티스에서, 메트릭 API(Metrics API) 는 자동 스케일링 및 비슷한 사용 사례를 지원하기 위한 기본적인 메트릭 집합을 제공한다.
이 API는 노드와 파드의 리소스 사용량 정보를 제공하며,
여기에는 CPU 및 메모리 메트릭이 포함된다.
메트릭 API를 클러스터에 배포하면, 쿠버네티스 API의 클라이언트는 이 정보에 대해 질의할 수 있으며,
질의 권한을 관리하기 위해 쿠버네티스의 접근 제어 메커니즘을 이용할 수 있다.
참고: 메트릭 API 및 이것이 제공하는 메트릭 파이프라인은
HPA / VPA 에 의한 자동 스케일링이 동작하는 데 필요한
최소한의 CPU 및 메모리 메트릭만을 제공한다.
더 많은 메트릭 집합을 제공하려면, 커스텀 메트릭 API 를 사용하는
추가 메트릭 파이프라인을 배포하여
기본 메트릭 API를 보충할 수 있다.
kubelet: 컨테이너 리소스 관리를 위한 노드 에이전트.
리소스 메트릭은 kubelet API 엔드포인트 /metrics/resource 및
/stats 를 사용하여 접근 가능하다.
요약 API: /stats 엔드포인트를 통해 사용할 수 있는
노드 별 요약된 정보를 탐색 및 수집할 수 있도록 kubelet이 제공하는 API
metrics-server: 각 kubelet으로부터 수집한 리소스 메트릭을 수집 및 집계하는 클러스터 애드온 구성 요소.
API 서버는 HPA, VPA 및 kubectl top 명령어가 사용할 수 있도록 메트릭 API를 제공한다.
metrics-server는 메트릭 API에 대한 기준 구현(reference implementation) 중 하나이다.
메트릭 API: 워크로드 오토스케일링에 사용되는 CPU 및 메모리 정보로의 접근을 지원하는 쿠버네티스 API.
이를 클러스터에서 사용하려면,
메트릭 API를 제공하는 API 확장(extension) 서버가 필요하다.
참고: cAdvisor는 cgroups으로부터 메트릭을 가져오는 것을 지원하며, 리눅스의 일반적인 컨테이너 런타임은 이를 지원한다.
만약 다른 리소스 격리 메커니즘(예: 가상화)을 사용하는 컨테이너 런타임을 사용한다면,
kubelet이 메트릭을 사용할 수 있기 위해서는
해당 컨테이너 런타임이
CRI 컨테이너 메트릭을 지원해야 한다.
메트릭 API
기능 상태:Kubernetes 1.8 [beta]
metrics-server는 메트릭 API에 대한 구현이다.
이 API는 클러스터 내 노드와 파드의 CPU 및 메모리 사용 정보에 접근할 수 있게 해 준다.
이것의 주 역할은 리소스 사용 메트릭을 쿠버네티스 오토스케일러 구성 요소에 제공하는 것이다.
다음은 minikube 노드에 대한 메트릭 API 요청 예시이며
가독성 향상을 위해 jq를 활용한다.
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes/minikube" | jq '.'
참고: 메트릭 API에 접근하려면 먼저 메트릭 API를 제공하는
metrics-server 또는 대체 어댑터를 배포해야 한다.
리소스 사용량 측정
CPU
CPU는 cpu 단위로 측정된 평균 코어 사용량 형태로 보고된다. 쿠버네티스에서 1 cpu는
클라우드 제공자의 경우 1 vCPU/코어에 해당하고, 베어메탈 인텔 프로세서의 경우 1 하이퍼-스레드에 해당한다.
이 값은 커널(Linux 및 Windows 커널 모두)에서 제공하는 누적 CPU 카운터에 대한
비율을 취하여 얻어진다.
CPU 값 계산에 사용된 타임 윈도우는 메트릭 API의 window 필드에 표시된다.
쿠버네티스가 어떻게 CPU 리소스를 할당하고 측정하는지 더 알아보려면,
CPU의 의미를 참고한다.
메모리
메모리는 메트릭을 수집하는 순간에 바이트 단위로 측정된 워킹 셋(working set) 형태로 보고된다.
이상적인 환경에서, "워킹 셋"은 메모리가 부족한 상태더라도 해제할 수 없는 사용 중인 메모리의 양이다.
그러나 워킹 셋의 계산 방법은 호스트 OS에 따라 다르며
일반적으로 추정치를 추출하기 위해 휴리스틱을 많이 사용한다.
컨테이너의 워킹 셋에 대한 쿠버네티스 모델은 컨테이너 런타임이 해당 컨테이너와 연결된 익명(anonymous) 메모리를 계산할 것으로 예상한다.
호스트 OS가 항상 페이지를 회수할 수는 없기 때문에,
워킹 셋 메트릭에는 일반적으로 일부 캐시된 (파일 기반) 메모리도 포함된다.
쿠버네티스가 어떻게 메모리 리소스를 할당하고 측정하는지 더 알아보려면,
메모리의 의미를 참고한다.
metrics-server
metrics-server는 kubelet으로부터 리소스 메트릭을 수집하고,
이를 HPA(Horizontal Pod Autoscaler) 및 VPA(Vertical Pod Autoscaler)가 활용할 수 있도록 쿠버네티스 API 서버 내에서 메트릭 API(Metrics API)를 통해 노출한다.
kubectl top 명령을 사용하여 이 메트릭을 확인해볼 수도 있다.
metrics-server는 쿠버네티스 API를 사용하여 클러스터의 노드와 파드를 추적한다.
metrics-server는 각 노드에 HTTP를 통해 질의하여 메트릭을 수집한다.
metrics-server는 또한 파드 메타데이터의 내부적 뷰를 작성하고, 파드 헬스(health)에 대한 캐시를 유지한다.
이렇게 캐시된 파드 헬스 정보는 metrics-server가 제공하는 확장 API(extension API)를 통해 이용할 수 있다.
HPA 질의에 대한 예시에서, 예를 들어 HPA 질의에 대한 경우,
metrics-server는 디플로이먼트의 어떤 파드가 레이블 셀렉터 조건을 만족하는지 판별해야 한다.
metrics-server는 각 노드로부터 메트릭을 수집하기 위해 kubelet API를 호출한다.
사용 중인 metrics-server 버전에 따라, 다음의 엔드포인트를 사용한다.
kubelet이 어떻게 노드 메트릭을 제공하는지, 그리고 쿠버네티스 API를 통해 이러한 메트릭에 어떻게 접근하는지 알아보려면,
노드 메트릭 데이터 문서를 참조한다.
2 - 리소스 모니터링 도구
애플리케이션을 스케일하여 신뢰할 수 있는 서비스를 제공하려면,
애플리케이션이 배포되었을 때 애플리케이션이 어떻게 동작하는지를 이해해야 한다.
컨테이너, 파드,
서비스,
그리고 전체 클러스터의 특성을 검사하여
쿠버네티스 클러스터 내의 애플리케이션 성능을 검사할 수 있다. 쿠버네티스는 각 레벨에서
애플리케이션의 리소스 사용량에 대한 상세 정보를 제공한다.
이 정보는 애플리케이션의 성능을 평가하고
병목 현상을 제거하여 전체 성능을 향상할 수 있게 해준다.
쿠버네티스에서 애플리케이션 모니터링은 단일 모니터링 솔루션에 의존하지 않는다.
신규 클러스터에서는, 리소스 메트릭 또는
완전한 메트릭 파이프라인으로 모니터링 통계를 수집할 수 있다.
리소스 메트릭 파이프라인
리소스 메트릭 파이프라인은
Horizontal Pod Autoscaler
컨트롤러와 같은 클러스터 구성요소나
kubectl top 유틸리티에 관련되어 있는
메트릭들로 제한된 집합을 제공한다. 이 메트릭은 경량의 단기 인메모리 저장소인
metrics-server에
의해서 수집되며 metrics.k8s.io API를 통해 노출된다.
metrics-server는 클러스터 상의 모든 노드를 발견하고
각 노드의 kubelet에
CPU와 메모리 사용량을 질의한다.
Kubelet은 쿠버네티스 마스터와 노드 간의 다리 역할을 하면서
머신에서 구동되는 파드와 컨테이너를 관리한다.
Kubelet은 각각의 파드를 해당하는 컨테이너에 매치시키고
컨테이너 런타임 인터페이스를 통해
컨테이너 런타임에서 개별 컨테이너의 사용량 통계를 가져온다.
컨테이너를 구현하기 위해 리눅스 cgroup 및 네임스페이스를 활용하는 컨테이너 런타임을 사용하며,
해당 컨테이너 런타임이 사용 통계치를 퍼블리싱 하지 않는 경우,
kubelet은 해당 통계치를 (cAdvisor의 코드 사용하여) 직접 조회 할 수 있다.
이런 통계가 어떻게 도착하든 kubelet은 취합된 파드 리소스 사용량 통계를
metric-server 리소스 메트릭 API를 통해 노출한다.
이 API는 kubelet의 인증이 필요한 읽기 전용 포트 상의
/metrics/resource/v1beta1에서 제공된다.
완전한 메트릭 파이프라인
완전한 메트릭 파이프라인은 보다 풍부한 메트릭에 접근할 수 있도록 해준다.
쿠버네티스는 Horizontal Pod Autoscaler와 같은 메커니즘을 활용해서 이런 메트릭에
대한 반응으로 클러스터의 현재 상태를 기반으로 자동으로 스케일링하거나 클러스터를
조정할 수 있다. 모니터링 파이프라인은 kubelet에서 메트릭을 가져와서 쿠버네티스에
custom.metrics.k8s.io와 external.metrics.k8s.io API를 구현한 어댑터를 통해
노출한다.
CNCF 프로젝트인 프로메테우스는 기본적으로 쿠버네티스, 노드, 프로메테우스 자체를 모니터링할 수 있다.
CNCF 프로젝트가 아닌 완전한 메트릭 파이프라인 프로젝트는 쿠버네티스 문서의 범위가 아니다.
노드 문제 감지기(Node Problem Detector) 는 노드의 헬스에 대해 모니터링 및 보고하는 데몬이다.
노드 문제 감지기를 데몬셋(DaemonSet) 혹은 스탠드얼론 데몬(standalone daemon)으로 실행할 수 있다.
노드 문제 감지기는 다양한 데몬으로부터 노드의 문제에 관한 정보를 다양한 데몬으로부터 수집하고,
이러한 컨디션들을 노드컨디션(NodeCondition) 및
이벤트(Event)형태로 API 서버에 보고한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와
통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고
있지 않다면,
minikube를 사용해서 생성하거나
다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
# 만약 노드 문제 감지기가 동작하고 있다면, 재생성 전 삭제한다kubectl delete -f https://k8s.io/examples/debug/node-problem-detector.yaml
kubectl apply -f https://k8s.io/examples/debug/node-problem-detector-configmap.yaml
참고: 이 접근법은 노드 문제 감지기를 kubectl로 시작했을 때에만 적용된다.
만약 노드 문제 감지기가 클러스터 애드온으로 실행된 경우, 설정 덮어쓰기가 지원되지 않는다.
애드온 매니저는 컨피그맵(ConfigMap)을 지원하지 않는다.
커널 모니터
커널 모니터는 노드 문제 감지기에서 지원하는 시스템 로그 모니터링 데몬이다.
커널 모니터는 커널 로그를 감시하며, 미리 설정된 규칙에 따라 알려진 커널 이슈를 감지한다.
커널 모니터는 config/kernel-monitor.json에
미리 설정된 규칙 모음과 커널 이슈를 매칭한다.
규칙 리스트는 확장 가능하다. 설정을 덮어쓰기 해 규칙 리스트를 확장할 수 있다.
신규 노드컨디션(NodeConditions) 추가하기
신규 NodeCondition를 지원하려면, config/kernel-monitor.json의 conditions필드 내 조건 정의를 생성해야한다.
예를 들면 아래와 같다.
신규 문제를 감지하려면 config/kernel-monitor.json의 rules필드를
신규 규칙 정의로 확장하면 된다.
{
"type": "temporary/permanent",
"condition": "NodeConditionOfPermanentIssue",
"reason": "CamelCaseShortReason",
"message": "regexp matching the issue in the kernel log"}
커널 로그 장치를 위한 경로 설정하기
운영 체제 (OS) 배포판의 커널 로그 경로를 확인한다.
리눅스 커널 로그 장치(log device)는 보통 /dev/kmsg와 같이 표시된다. 하지만, 로그 경로 장소는 OS 배포판마다 상이하다.
config/kernel-monitor.json 의 log 필드는 컨테이너 내부의 로그 경로를 나타낸다.
log 필드를 노드 문제 감지기가 감시하는 장치 경로와 일치하도록 구성하면 된다.
기타 로그 포맷 지원 추가하기
커널 모니터는 커널 로그의 내부 데이터 구조를 해석하기 위해
Translator 플러그인을 사용한다.
신규 로그 포맷을 사용하기 위해 신규 해석기를 구현할 수 있다.
권장 사항 및 제약 사항
노드 헬스를 모니터링하기 위해 클러스터에 노드 문제 탐지기를 실행할 것을 권장한다.
노드 문제 감지기를 실행할 때, 각 노드에 추가 리소스 오버헤드가 발생할 수 있다.
다음과 같은 이유 때문에 일반적으로는 문제가 없다.
커널 로그는 비교적 천천히 늘어난다.
노드 문제 감지기에는 리소스 제한이 설정되어 있다.
높은 부하가 걸리더라도, 리소스 사용량은 허용 가능한 수준이다. 추가 정보를 위해 노드 문제 감지기의
벤치마크 결과를 살펴보자.
4 - crictl로 쿠버네티스 노드 디버깅하기
기능 상태:Kubernetes v1.11 [stable]
crictl은 CRI-호환 컨테이너 런타임에 사용할 수 있는 커맨드라인 인터페이스이다.
쿠버네티스 노드에서 컨테이너 런타임과 애플리케이션을 검사하고
디버그하는 데 사용할 수 있다.
crictl과 그 소스는 cri-tools 저장소에서 호스팅한다.
시작하기 전에
crictl은 CRI 런타임이 있는 리눅스 운영체제를 필요로 한다.
crictl 설치하기
cri-tools 릴리스 페이지에서
다양한 아키텍처 별로 압축된 crictl 아카이브(archive)를 다운로드할 수 있다.
설치된 쿠버네티스 버전에 해당하는 버전을 다운로드한다.
/usr/local/bin/와 같은 시스템 경로의 위치에
압축을 푼다.
일반적인 사용법
crictl 커맨드에는 여러 하위 커맨드와 런타임 플래그가 있다.
자세한 내용은 crictl help 또는 crictl <subcommand> help를 참조한다.
아래 내용 중 하나를 통해 crictl의 엔드포인트를 설정할 수 있다.
--runtime-endpoint와 --image-endpoint 플래그 설정.
CONTAINER_RUNTIME_ENDPOINT와 IMAGE_SERVICE_ENDPOINT 환경 변수
설정.
구성 파일 /etc/crictl.yaml에 엔드포인트 설정.
다른 파일을 지정하기 위해서는 crictl을 실행할 때 --config=PATH_TO_FILE 플래그를 사용한다.
참고: 엔드포인트를 설정하지 않으면,
crictl이 알려진 엔드포인트 목록에 연결을 시도하므로 성능에 영향을 줄 수 있다.
서버에 연결할 때 구성 파일에서 timeout 또는 debug 값을 명시하거나,
--timeout 그리고 --debug 커맨드라인 플래그를 사용하여
타임아웃 값을 지정하고 디버깅을 활성화하거나 비활성화할 수 있다.
현재 구성을 보거나 편집하려면 /etc/crictl.yaml의 내용을 보거나 편집한다.
예를 들어,
containerd 컨테이너 런타임 사용 시 구성은 아래와 유사하다.
경고: 구동 중인 쿠버네티스 클러스터에서 crictl을 사용하여 파드 샌드박스(sandbox)나 컨테이너를 만들게 되면,
결국에는 kubelet이 그것들을 삭제하게 된다.
crictl은 일반적인 워크플로우 툴이 아니라 디버깅에 유용한 툴임을 명심해야 한다.
파드 목록 조회
모든 파드의 목록 조회
crictl pods
출력은 다음과 유사하다.
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
926f1b5a1d33a About a minute ago Ready sh-84d7dcf559-4r2gq default 0
4dccb216c4adb About a minute ago Ready nginx-65899c769f-wv2gp default 0
a86316e96fa89 17 hours ago Ready kube-proxy-gblk4 kube-system 0
919630b8f81f1 17 hours ago Ready nvidia-device-plugin-zgbbv kube-system 0
이름으로 파드의 목록 조회
crictl pods --name nginx-65899c769f-wv2gp
출력은 다음과 유사하다.
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
레이블로 파드의 목록 조회
crictl pods --label run=nginx
출력은 다음과 유사하다.
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 7 minutes ago Running sh 1
9c5951df22c78 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 8 minutes ago Exited sh 0
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 8 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 18 hours ago Running kube-proxy 0
실행 중인 컨테이너 목록 조회
crictl ps
출력은 다음과 유사하다.
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 6 minutes ago Running sh 1
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 7 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 17 hours ago Running kube-proxy 0
쿠버네티스 감사(auditing) 는 클러스터의 작업 순서를 문서화하는 보안 관련 시간별 레코드 세트를 제공한다.
클러스터는 사용자, 쿠버네티스 API를 사용하는 애플리케이션 및
컨트롤 플레인 자체에서 생성된 활동을 감사한다.
감사를 통해 클러스터 관리자는 다음 질문에 답할 수 있다.
무슨 일이 일어났는지?
언제 일어난 일인지?
누가 시작했는지?
어떤 일이 있었는지?
어디서 관찰되었는지?
어디서부터 시작되었는지?
그래서 어디까지 갔는지?
감사 기록은 kube-apiserver
컴포넌트 내에서 수명주기를 시작한다.
실행의 각 단계에서 각 요청은 감사 이벤트를 생성하고,
감사 이벤트는 특정 정책에 따라 사전 처리되고 백엔드에 기록된다.
정책은 기록된 내용을 결정하고 백엔드는 기록을 유지한다.
현재 백엔드 구현에는 로그 파일 및
웹훅이 포함된다.
각 요청들은 연관된 단계(stage) 와 함께 기록될 수 있다. 정의된 단계는 다음과 같다.
RequestReceived - 감사 핸들러가 요청을 수신한 직후,
그리고 핸들러 체인으로 위임되기 전에
생성되는 이벤트에 대한 단계이다.
ResponseStarted - 응답 헤더는 전송되었지만,
응답 본문(body)은 전송되기 전인 단계이다.
이 단계는 오래 실행되는 요청(예: watch)에 대해서만 생성된다.
ResponseComplete - 응답 내용이 완료되었으며,
더 이상 바이트가 전송되지 않을 때의 단계이다.
감사 로깅 기능은 감사에 필요한 일부 컨텍스트가 요청마다
저장되기 때문에 API 서버의 메모리 사용량을 증가시킨다.
메모리 소비량은 감사 로깅 구성에 따라 다르다.
감사 정책
감사 정책은 기록해야 하는 이벤트와 포함해야 하는
데이터에 대한 규칙을 정의한다. 감사 정책 오브젝트 구조는
audit.k8s.io API 그룹에 정의되어 있다.
이벤트가 처리되면 규칙 목록과 순서대로 비교된다.
첫번째 일치 규칙은 이벤트의 감사 수준(audit level) 을 설정한다.
정의된 감사 수준은 다음과 같다.
Request - 이벤트 메타데이터 및 요청 본문을 로깅하지만 응답 본문은 로깅하지 않는다.
리소스 외의 요청에는 적용되지 않는다.
RequestResponse - 이벤트 메타데이터 및 요청/응답 본문을 로깅한다.
리소스 외의 요청에는 적용되지 않는다.
--audit-policy-file 플래그를 사용하여 정책이 포함된 파일을
kube-apiserver에 전달할 수 있다. 플래그를 생략하면 이벤트가 기록되지 않는다.
감사 정책 파일에 rules 필드 반드시 가 제공되어야 한다.
규칙이 없는(0개인) 정책은 적절하지 않은(illegal) 것으로 간주된다.
apiVersion:audit.k8s.io/v1# 필수사항임.kind:Policy# Request Received 단계의 모든 요청에 대해 감사 이벤트를 생성하지 않음.omitStages:- "RequestReceived"rules:# RequestResponse 수준에서 파드 변경 사항 기록- level:RequestResponseresources:- group:""# 리소스 "파드" 가 RBAC 정책과 부합하는 파드의 하위 리소스에 대한# 요청과 일치하지 않음.resources:["pods"]# 메타데이터 수준에서 "pods/log", "pods/status"를 기록함.- level:Metadataresources:- group:""resources:["pods/log","pods/status"]# "controller-leader" 라는 컨피그맵에 요청을 기록하지 않음."- level:Noneresources:- group:""resources:["configmaps"]resourceNames:["controller-leader"]# 엔드포인트 또는 서비스의 "system:kube-proxy"에 의한 감시 요청 기록하지 않음.- level:Noneusers:["system:kube-proxy"]verbs:["watch"]resources:- group:""# 핵심 API 그룹resources:["endpoints","services"]# 인증된 요청을 특정 리소스가 아닌 URL 경로에 기록하지 않음.- level:NoneuserGroups:["system:authenticated"]nonResourceURLs:- "/api*"# 와일드카드 매칭(wildcard matching).- "/version"# kube-system에 컨피그맵 변경 사항의 요청 본문을 기록함.- level:Requestresources:- group:""# 핵심 API 그룹resources:["configmaps"]# 이 정책은 "kube-system" 네임스페이스의 리소스에만 적용됨.# 빈 문자열 "" 은 네임스페이스가 없는 리소스를 선택하는데 사용할 수 있음.namespaces:["kube-system"]# 메타데이터 수준에서 다른 모든 네임스페이스의 컨피그맵과 시크릿 변경 사항을 기록함.- level:Metadataresources:- group:""# 핵심 API 그룹resources:["secrets","configmaps"]# 요청 수준에서 코어 및 확장에 있는 다른 모든 리소스를 기록함.- level:Requestresources:- group:""# 핵심 API 그룹- group:"extensions"# 그룹의 버전을 기재하면 안 된다.# 메타데이터 수준에서 다른 모든 요청을 기록하기 위한 모든 수집 정책.- level:Metadata# 이 정책에 해당하는 감시자와 같은 장기 실행 요청은# RequestReceived에서 감사 이벤트를 생성하지 않음.omitStages:- "RequestReceived"
최소 감사 정책 파일을 사용하여 Metadata 수준에서 모든 요청을 기록할 수 있다.
# Log all requests at the Metadata level.apiVersion:audit.k8s.io/v1kind:Policyrules:- level:Metadata
자체 감사 프로필을 만드는 경우 Google Container-Optimized OS에 대한 감사 프로필을 시작점으로 사용할 수 있다.
감사 정책 파일을 생성하는 configure-helper.sh
스크립트를 확인하면 된다. 스크립트로 대부분의 감사 정책 파일을 볼 수 있다.
패치의 경우 요청 내용은 적절한 쿠버네티스 API 오브젝트를 포함하는 JSON 오브젝트가 아니라
패치 작업을 포함하는 JSON 배열이다. 예를 들어 다음 요청 내용은
/apis/batch/v1/namespaces/some-namespace/jobs/some-job-name에 대한 유효한 패치 요청이다.
웹훅 감사 백엔드는 원격 웹 API로 감사 이벤트를 전송하는데, 이는 인증 수단을 포함하여
쿠버네티스 API의 한 형태로 간주된다.
다음 kube-apiserver 플래그를 사용하여 웹훅 감사 백엔드를 구성할 수 있다.
--audit-webhook-config-file 은 웹훅 구성이 있는 파일의 경로를 지정한다.
웹훅 구성은 효과적으로 전문화된
kubeconfig이다.
--audit-webhook-initial-backoff 는 첫 번째 실패한 요청 후 다시 시도하기 전에 대기할 시간을 지정한다.
이후 요청은 지수의 백오프로 재시도 된다.
웹훅 구성 파일은 kubeconfig 형식을 사용하여
서비스의 원격 주소와 서비스에 연결하는 데 사용되는 자격 증명을 지정한다.
이벤트 배치
로그 및 웹 훅 백엔드는 모두 배치를 지원한다. 웹훅 사용을 예로 들면, 다음은 사용 가능한 플래그 목록이다.
로그 백엔드에 대해 동일한 플래그를 가져오려면 플래그 이름에 있는 webhook 을 log 로 바꾼다.
기본적으로 배치 기능은 webhook 에서 활성화되고 log 에서 비활성화된다. 마찬가지로, 기본적으로
쓰로틀링은 webhook 에서는 활성화되고 log 에서는 비활성화된다.
--audit-webhook-mode 은 버퍼링 전략을 정의한다. 다음 중 하나이다.
batch - 이벤트를 버퍼링하고 비동기식으로 배치한다. 이것이 기본값이다.
blocking - 각 개별 이벤트를 처리할 때 API 서버 응답을 차단한다.
blocking-strict - blocking과 동일하지만, RequestReceived 단계에서 감사 로깅 중에 오류가 발생하면
kube-apiserver에 대한 전체 요청이 실패한다.
다음 플래그는 batch 모드에서만 사용된다.
--audit-webhook-batch-buffer-size 는 배치하기 전에 버퍼링할 이벤트 수를 정의한다.
들어오는 이벤트의 비율이 버퍼를 초과하면 이벤트가 삭제된다.
--audit-webhook-batch-max-size 는 한 배치의 최대 이벤트 수를 정의한다.
--audit-webhook-batch-max-wait 는 대기열에서 이벤트를 무조건 배치하기 전에
대기할 최대 시간을 정의한다.
--audit-webhook-batch-throttle-qps 는 초당 생성되는 최대 평균 배치 수를
정의한다.
--audit-webhook-batch-throttle-burst 는 허용된 QPS가 이전에 충분히 활용되지 않은 경우
동시에 생성되는 최대 배치 수를 정의한다.
파라미터 튜닝
파라미터는 API 서버의 로드를 수용할 수 있도록 설정해야 한다.
예를 들어 kube-apiserver가 초당 100건의 요청을 수신하고 각 요청이
ResponseStarted 와 ResponseComplete 단계에서만 감사되는 경우 초당 생성되는 ≅200건의 감사 이벤트를 고려해야 한다.
일괄적으로 최대 100개의 이벤트가 있다고 가정할 때
초당 최소 2개의 쿼리 조절 수준을 설정해야 한다.
백엔드가 이벤트를 쓰는 데 최대 5초가 걸릴 수 있다고 가정하면 버퍼크기를 최대 5초의 이벤트를 보유하도록 설정해야 한다.
즉, 10개의 배치 또는 100개의 이벤트이다.
그러나 대부분의 경우 기본 매개 변수만 있으면 충분하며 수동으로 설정할 필요가 없다.
kube-apiserver에서 노출된 다음과 같은 프로메테우스 메트릭과 로그에서
감사 하위 시스템의 상태를 모니터링할 수 있다.
apiserver_audit_event_total 의 메트릭에는 내보낸 감사 이벤트의 총 수가 포함된다.
apiserver_audit_error_total 의 메트릭에는 내보내기 중 오류로 인해 삭제된 총 이벤트
수가 포함된다.
로그 항목 자르기
로그 및 웹훅 백엔드는 모두 로깅되는 이벤트의 크기 제한을 지원한다.
예를 들어 로그 백엔드에 사용할 수 있는 플래그 목록은 다음과 같다.
audit-log-truncate-enabled 는 이벤트 및 자르기 배치가 활성화 되었는지 여부를 나타낸다.
audit-log-truncate-max-batch-size 는 기본 백엔드로 전송되는 배치의 바이트 단위의 최대 크기이다.
audit-log-truncate-max-event-size 는 기본 백엔드로 전송된 감사 이벤트의 바이트 단위의 최대 크기이다.
기본적으로 webhook 과 log 모두에서 자르기 기능이 비활성화되어 있으므로 이 기능을 활성화 하기 위해
클러스터 관리자는 audit-log-truncate-enabled 또는 audit-webhook-truncate-enabled 를 설정해야 한다.
참고:
이 섹션은 쿠버네티스에 필요한 기능을 제공하는 써드파티 프로젝트와 관련이 있다. 쿠버네티스 프로젝트 작성자는 써드파티 프로젝트에 책임이 없다. 이 페이지는 CNCF 웹사이트 가이드라인에 따라 프로젝트를 알파벳 순으로 나열한다. 이 목록에 프로젝트를 추가하려면 변경사항을 제출하기 전에 콘텐츠 가이드를 읽어본다.
쿠버네티스 애플리케이션은 일반적으로 각각 자체 컨테이너에서 실행되는 여러 개의 개별 서비스로 구성된다. 원격 쿠버네티스 클러스터 상에서 이러한 서비스를 개발하고 디버깅하려면 디버깅 도구를 실행하기 위해 동작 중인 컨테이너의 셸(shell)에 접근해야 하기 때문에 번거로울 수 있다.
텔레프레즌스(telepresence)는 원격 쿠버네티스 클러스터로 서비스를 프록시하면서 로컬에서 서비스를 개발 및 디버깅하는 과정을 용이하게 하는 도구이다. 텔레프레즌스를 사용하면 로컬 서비스에 디버거 및 IDE와 같은 사용자 지정 도구를 사용할 수 있고 원격 클러스터에서 실행되는 컨피그맵(ConfigMap), 시크릿(Secret) 및 서비스(Service)에 대한 전체 접근 권한을 서비스에 제공할 수 있다.
이 문서는 텔레프레즌스를 사용하여 원격 클러스터에서 실행 중인 서비스를 로컬로 개발하고 디버그하는 방법을 설명한다.
텔레프레즌스를 설치한 후 텔레프레즌스 커넥트(telepresence connect)를 실행하여 데몬을 실행하고 로컬 워크스테이션을 클러스터에 연결한다.
$ telepresence connect
Launching Telepresence Daemon
...
Connected to context default (https://<cluster public IP>)
쿠버네티스 구문을 사용하여 서비스에 curl이 가능하다. 예, curl -ik https://kubernetes.default
기존 서비스 개발 또는 디버깅
쿠버네티스에서 애플리케이션을 개발할 때 일반적으로 단일 서비스를 프로그래밍하거나 디버그한다. 서비스를 테스트 및 디버깅하기 위해 다른 서비스에 접근이 필요할 수 있다. 지속적 배포(continuous deployment) 파이프라인을 사용하는 것도 한 가지 옵션이지만, 가장 빠른 배포 파이프라인이라도 프로그래밍 또는 디버그 주기에 지연이 발생할 수 있다.
telepresence intercept $SERVICE_NAME --port $LOCAL_PORT:$REMOTE_PORT 명령을 사용하여 원격 서비스 트래픽을 다시 라우팅하기 위한 "인터셉트(intercept)"를 생성한다.
아래의 각 항목에 대한 설명을 참고한다.
$SERVICE_NAME은 로컬 서비스의 이름이다.
$LOCAL_PORT는 서비스가 로컬 워크스테이션에서 실행 중인 포트이다.
$REMOTE_PORT는 서비스가 클러스터에서 수신하는 포트이다.
이 명령을 실행하면 원격 쿠버네티스 클러스터의 서비스 대신 로컬 서비스에 원격 트래픽을 보내도록 텔레프레즌스에 지시한다. 서비스 소스 코드를 로컬에서 편집하고 저장하여 원격 애플리케이션에 접근할 때 해당 변경 사항이 즉시 적용되는지 확인한다. 디버거 또는 기타 로컬 개발 도구를 사용하여 로컬 서비스를 실행할 수도 있다.
텔레프레즌스는 어떻게 작동하는가?
Telepresence는 원격 클러스터에서 실행 중인 기존 애플리케이션의 컨테이너 옆에 트래픽 에이전트 사이드카(sidecar)를 설치한다. 그런 다음 파드로 들어오는 모든 트래픽 요청을 캡처하고, 이를 원격 클러스터의 애플리케이션에 전달하는 대신, 모든 트래픽(글로벌 인터셉트를 생성하는 경우) 또는 일부 트래픽(개인 인터셉트를 생성하는 경우)을 로컬 개발 환경으로 라우팅한다.
다음 내용
핸즈온 튜토리얼에 관심이 있다면 구글 쿠버네티스 엔진 상의 방명록 애플리케이션을 로컬로 개발하는 과정을 안내하는 이 튜토리얼을 확인한다.
가상 머신을 사용하는 경우,
모든 VM 네트워크 어댑터에 MAC 스푸핑이 활성화되어 있는지 확인한다.
내 윈도우 파드가 외부 리소스를 ping 할 수 없다.
윈도우 파드에는 현재 ICMP 프로토콜용으로 프로그래밍된 아웃바운드 규칙이 없다.
그러나 TCP/UDP는 지원된다.
클러스터 외부 리소스에 대한 연결을 시연하려는 경우,
ping <IP>를 대응되는 curl <IP>명령으로 대체한다.
여전히 문제가 발생하는 경우,
cni.conf의 네트워크 구성에 특별히 추가 확인이 필요하다.
언제든지 이 정적 파일을 편집할 수 있다.
구성 업데이트는 새로 생성된 모든 쿠버네티스 리소스에 적용된다.
쿠버네티스 네트워킹 요구
사항(쿠버네티스 모델 참조)
중 하나는
클러스터 통신이 NAT 없이 내부적으로 발생해야 한다는 것이다.
이 요구 사항을 준수하기 위해
아웃바운드 NAT가 발생하지 않도록 하는
모든 통신에 대한 ExceptionList가 있다.
그러나 이것은 쿼리하려는 외부 IP를 ExceptionList에서 제외해야 함도 의미한다.
그래야만 윈도우 파드에서 발생하는 트래픽이 제대로 SNAT 되어 외부에서 응답을 받는다.
이와 관련하여 cni.conf의 ExceptionList는 다음과 같아야 한다.
이는 윈도우에서 현재 네트워킹 스택의 알려진 제약 사항이다. 그러나 윈도우 파드는 서비스 IP에 접근할 수 있다.
kubelet을 시작할 때 네트워크 어댑터를 찾을 수 없다.
윈도우 네트워킹 스택에는 쿠버네티스 네트워킹이 작동하기 위한 가상 어댑터가 필요하다.
(어드민 셸에서) 다음 명령이 결과를 반환하지 않으면,
Kubelet이 작동하는 데 필요한 필수 구성 요소인 가상 네트워크 생성이 실패한 것이다.
Get-HnsNetwork | ? Name -ieq"cbr0"Get-NetAdapter | ? Name -Like"vEthernet (Ethernet*"
호스트 네트워크 어댑터가 "Ethernet"이 아닌 경우, 종종 start.ps1 스크립트의
InterfaceName 파라미터를 수정하는 것이 좋다.
그렇지 않으면 start-kubelet.ps1 스크립트의 출력을 참조하여 가상 네트워크 생성 중에 오류가 있는지 확인한다.
kubectl port-forward가 "unable to do port forwarding: wincat not found" 에러와 함께 실패한다.
이 기능은 퍼즈 인프라 컨테이너 mcr.microsoft.com/oss/kubernetes/pause:3.6에
wincat.exe를 포함시킴으로써 쿠버네티스 1.15에서 구현되었다.
지원되는 쿠버네티스 버전을 사용하고 있는지 확인한다.
퍼즈 인프라 컨테이너를 직접 빌드하려면
wincat을 포함시켜야 한다.
이것은 플란넬이 제대로 실행되지 않았음을 나타낸다.
flanneld.exe를 다시 시작하거나
쿠버네티스 마스터의 /run/flannel/subnet.env에서 윈도우 워커 노드의 C:\run\flannel\subnet.env로 파일을 수동으로 복사할 수 있고,
FLANNEL_SUBNET 행을 다른 숫자로 수정한다.
예를 들어, 노드 서브넷 10.244.4.1/24가 필요한 경우 다음과 같이 설정한다.