쿠버네티스 클러스터에서 sysctl 사용하기
쿠버네티스 클러스터에서 sysctl 사용하기 (Using sysctls in a Kubernetes Cluster)
기능 상태: Kubernetes v1.21부터 Stable.
이 문서는 sysctl 인터페이스를 사용해 쿠버네티스 클러스터 안에서 커널 파라미터를 구성하고 사용하는 방법을 설명해요.
참고: 쿠버네티스 버전 1.23부터 kubelet은 sysctl 이름의 구분자로
/또는.을 지원해요. 쿠버네티스 버전 1.25부터 Pod에 대한 Sysctls 설정은 슬래시가 있는 sysctl 설정을 지원해요. 예를 들어 같은 sysctl 이름을 구분자로 마침표를 쓴kernel.shm_rmid_forced로, 또는 슬래시를 구분자로 쓴kernel/shm_rmid_forced로 표현할 수 있어요. 더 자세한 sysctl 파라미터 변환 방법은 Linux man-pages 프로젝트의 sysctl.d(5) 페이지를 참고하세요.
출처: 문서
본문
시작하기 전에 (Before you begin)
참고:
sysctl은 다양한 커널 파라미터를 구성하는 데 사용되는 Linux 전용 명령줄 도구이며, 비-Linux 운영 체제에서는 사용할 수 없어요.
쿠버네티스 클러스터가 필요하고, kubectl 명령줄 도구가 클러스터와 통신하도록 구성돼 있어야 해요. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 두 개 이상 있는 클러스터에서 실행하는 것을 권장해요. 아직 클러스터가 없다면 minikube로 만들거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있어요.
- iximiuz Labs
- Killercoda
- KodeKloud
일부 단계에서는 클러스터에서 실행되는 kubelet의 명령줄 옵션을 다시 구성할 수 있어야 해요.
모든 Sysctl 파라미터 나열하기 (Listing all Sysctl Parameters)
Linux에서 sysctl 인터페이스는 관리자가 런타임에 커널 파라미터를 수정할 수 있게 해줘요. 파라미터는 /proc/sys/ 가상 프로세스 파일 시스템을 통해 사용할 수 있어요. 파라미터는 다음과 같은 다양한 서브시스템을 다룬답니다.
- kernel (공통 접두사:
kernel.) - networking (공통 접두사:
net.) - virtual memory (공통 접두사:
vm.) - MDADM (공통 접두사:
dev.) - 더 많은 서브시스템은 Kernel 문서에 설명돼 있어요.
모든 파라미터 목록을 얻으려면 다음을 실행할 수 있어요.
sudo sysctl -a
안전한 Sysctl과 안전하지 않은 Sysctl (Safe and Unsafe Sysctls)
쿠버네티스는 sysctl을 안전(safe) 또는 안전하지 않음(unsafe)으로 분류해요. 적절한 네임스페이싱 외에도, 안전한 sysctl은 같은 노드의 파드 사이에서 적절히 분리돼야 해요. 이는 한 파드에 안전한 sysctl을 설정하는 것이
- 노드의 다른 어떤 파드에도 영향을 주지 않아야 하고
- 노드의 건강을 해치도록 허용하면 안 되고
- 파드의 리소스 한도 밖에서 CPU나 메모리 리소스를 얻도록 허용하면 안 된다는 뜻이에요.
대부분의 네임스페이스된 sysctl이 반드시 안전한 것으로 간주되지는 않아요. 안전한 집합에서 지원되는 sysctl은 다음과 같아요.
kernel.shm_rmid_forced;net.ipv4.ip_local_port_range;net.ipv4.tcp_syncookies;net.ipv4.ping_group_range(쿠버네티스 1.18부터);net.ipv4.ip_unprivileged_port_start(쿠버네티스 1.22부터);net.ipv4.ip_local_reserved_ports(쿠버네티스 1.27부터, 커널 3.16+ 필요);net.ipv4.tcp_keepalive_time(쿠버네티스 1.29부터, 커널 4.5+ 필요);net.ipv4.tcp_fin_timeout(쿠버네티스 1.29부터, 커널 4.6+ 필요);net.ipv4.tcp_keepalive_intvl(쿠버네티스 1.29부터, 커널 4.5+ 필요);net.ipv4.tcp_keepalive_probes(쿠버네티스 1.29부터, 커널 4.5+ 필요);net.ipv4.tcp_rmem(쿠버네티스 1.32부터, 커널 4.15+ 필요);net.ipv4.tcp_wmem(쿠버네티스 1.32부터, 커널 4.15+ 필요);net.ipv4.tcp_slow_start_after_idle(쿠버네티스 1.37부터, 커널 4.15+ 필요);net.ipv4.tcp_notsent_lowat(쿠버네티스 1.37부터, 커널 4.6+ 필요).
참고: 안전한 sysctl 집합에는 몇 가지 예외가 있어요.
net.*sysctl은 호스트 네트워킹이 활성화된 상태에서는 허용되지 않아요.net.ipv4.tcp_syncookiessysctl은 Linux 커널 버전 4.5 이하에서는 네임스페이스되지 않아요.
이 목록은 kubelet이 더 나은 격리 메커니즘을 지원할 때 향후 쿠버네티스 버전에서 확장될 거예요.
안전하지 않은 Sysctl 활성화하기 (Enabling Unsafe Sysctls)
모든 안전한 sysctl은 기본적으로 활성화돼요. 모든 안전하지 않은 sysctl은 기본적으로 비활성화되며, 클러스터 관리자가 노드별로 수동으로 허용해야 해요. 비활성화된 안전하지 않은 sysctl이 있는 Pod는 스케줄링되지만 시작에 실패해요.
위 경고를 명심하고, 클러스터 관리자는 고성능 또는 실시간 애플리케이션 튜닝 같은 아주 특별한 상황을 위해 특정 안전하지 않은 sysctl을 허용할 수 있어요. 안전하지 않은 sysctl은 kubelet의 플래그로 노드별로 활성화돼요. 예를 들어:
kubelet --allowed-unsafe-sysctls \
'kernel.msg*,net.core.somaxconn' ...
Minikube의 경우 extra-config 플래그로 이 작업을 할 수 있어요.
minikube start --extra-config="kubelet.allowed-unsafe-sysctls=kernel.msg*,net.core.somaxconn"...
이런 방식으로 네임스페이스된 sysctl만 활성화할 수 있어요.
Pod에 Sysctl 설정하기 (Setting Sysctls for a Pod)
오늘날 Linux 커널에서는 많은 sysctl이 네임스페이스돼 있어요. 즉, 노드의 각 파드에 대해 독립적으로 설정할 수 있다는 뜻이에요. 쿠버네티스 안에서는 파드 securityContext를 통해서만 네임스페이스된 sysctl을 구성할 수 있어요.
다음 sysctl은 네임스페이스되는 것으로 알려져 있어요. 이 목록은 Linux 커널의 향후 버전에서 바뀔 수 있어요.
kernel.shm*,kernel.msg*,kernel.sem,fs.mqueue.*,- 컨테이너 네트워킹 네임스페이스에서 설정할 수 있는
net.*. 단, 예외가 있어요(예:net.netfilter.nf_conntrack_max와net.netfilter.nf_conntrack_expect_max는 컨테이너 네트워킹 네임스페이스에서 설정할 수 있지만 Linux 5.12.2 이전에는 네임스페이스되지 않아요).
네임스페이스가 없는 sysctl은 노드 레벨 sysctl이라고 불러요. 이를 설정해야 한다면 각 노드의 운영 체제에서 수동으로 구성하거나, privileged 컨테이너가 있는 DaemonSet을 사용해야 해요.
네임스페이스된 sysctl을 구성하려면 파드 securityContext를 사용해요. securityContext는 같은 파드의 모든 컨테이너에 적용돼요.
이 예시는 파드 securityContext를 사용해 안전한 sysctl kernel.shm_rmid_forced와 두 개의 안전하지 않은 sysctl net.core.somaxconn과 kernel.msgmax를 설정해요. 사양에서는 안전한 sysctl과 안전하지 않은 sysctl의 구분이 없어요.
경고: 시스템 운영 체제를 불안정하게 만들지 않도록, sysctl 파라미터를 그 효과를 이해한 후에만 수정하세요.
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
spec:
securityContext:
sysctls:
- name: kernel.shm_rmid_forced
value: "0"
- name: net.core.somaxconn
value: "1024"
- name: kernel.msgmax
value: "65536"
...
경고: 안전하지 않다는 본질 때문에, 안전하지 않은 sysctl의 사용은 본인 책임이며 컨테이너의 잘못된 동작, 리소스 부족 또는 노드의 완전한 고장 같은 심각한 문제로 이어질 수 있어요.
특수한 sysctl 설정이 있는 노드는 클러스터 내에서 tainted로 간주하고, 해당 sysctl 설정이 필요한 파드만 그 노드에 스케줄링하는 것이 좋은 관례예요. 이를 구현하려면 쿠버네티스 taints 및 toleration 기능을 사용하는 것이 권장돼요.
안전하지 않은 sysctl이 있는 파드는 해당 두 개의 안전하지 않은 sysctl을 명시적으로 활성화하지 않은 어떤 노드에서도 시작에 실패할 거예요. 노드 레벨 sysctl과 마찬가지로 taints 및 toleration 기능이나 노드의 taints를 사용해 그런 파드를 올바른 노드에 스케줄링하는 것을 권장해요.
모든 Pod에 Sysctl 설정하기 (Setting Sysctls for All Pods)
기능 상태: Kubernetes v1.37부터 Alpha; 기본적으로 비활성화됨.
이 기능을 사용하려면, 당신(또는 클러스터 관리자)이 클러스터의 모든 관련 컴포넌트에 대해 DefaultPodSysctls 기능 게이트를 활성화해야 해요. 기능 게이트 활성화 또는 비활성화에 대한 자세한 내용은 "Enable Or Disable Feature Gates"를 참고하세요.
static Pod를 포함해 Linux 노드에서 실행되는 모든 Pod에 kubelet이 적용하는 기본 커널 파라미터(sysctls) 집합을 구성할 수 있어요. 이는 노드 관리자가 모든 Pod 사양에 개별적으로 securityContext.sysctls를 설정할 필요 없이, 노드 또는 노드 그룹의 모든 워크로드에 걸쳐 일관된 커널 파라미터 튜닝을 강제해야 할 때(예: 고성능 네트워킹을 위한 TCP 버퍼 크기 조정) 유용해요.
이 기능을 사용하려면 kubelet에 DefaultPodSysctls 기능 게이트를 활성화하고 KubeletConfiguration의 defaultPodSysctls 필드에 키-값 쌍을 지정해요.
defaultPodSysctls 필드는 모든 네임스페이스된 sysctl(kernel.shm*, kernel.msg*, kernel.sem, kernel.domainname, fs.mqueue.*, net.*, user.*)을 지원하며, 안전한 sysctl과 안전하지 않은 sysctl 모두를 다뤄요. 이 기본값은 노드 관리자가 kubelet에서 직접 구성하기 때문에, allowedUnsafeSysctls에서 안전하지 않은 sysctl을 허용 목록에 추가할 필요가 없어요.
다음 예시는 kubelet이 노드의 모든 Pod에 여러 네임스페이스된 서브시스템(네트워킹, IPC, 사용자 네임스페이스)에 걸쳐 기본 sysctl을 적용하도록 구성해요.
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
DefaultPodSysctls: true
defaultPodSysctls:
# Network namespace sysctls (skipped if Pod uses hostNetwork: true)
net.ipv4.ip_forward: "1"
net.ipv4.tcp_rmem: "4096 87380 16777216"
net.ipv4.tcp_wmem: "4096 65536 16777216"
net.core.somaxconn: "1024"
# IPC namespace sysctls (skipped if Pod uses hostIPC: true)
kernel.shmall: "1048576"
kernel.msgmax: "65536"
kernel.sem: "250 32000 32 128"
fs.mqueue.msg_max: "1024"
# User namespace sysctls (skipped if Pod shares the host user namespace)
user.max_user_namespaces: "1000"
우선순위와 오버라이딩 (Precedence and Overriding)
Pod의 spec.securityContext.sysctls에 명시적으로 설정된 값은 항상 kubelet의 defaultPodSysctls에 지정된 일치하는 기본값을 덮어써요. 오버라이드는 키별로 개별적으로 적용돼요. Pod가 defaultPodSysctls에도 정의된 sysctl에 값을 지정하면, 그 특정 sysctl에 대해서는 Pod 레벨 설정이 우선하고 다른 기본값은 계속 적용돼요. 연결된 sysctl 설정 그룹은 없다는 점을 유의하세요. 워크로드가 관련 그룹(예: 네트워킹 버퍼 크기)의 일부인 sysctl을 오버라이드한다면, Pod 사양이 필요에 따라 모든 관련 설정을 반영해야 해요.
호스트 네임스페이스와 필터링 (Host Namespaces and Filtering)
kubelet은 Pod가 해당 서브시스템에 대해 별도의 네임스페이스에서 실행되는 경우에만 Pod 샌드박스 생성 중에 기본 sysctl을 적용해요. Pod가 호스트 네임스페이스를 공유한다면 그 네임스페이스에 대한 기본 sysctl은 그 Pod에 대해 건너뛰어져요.
net.*sysctl은 Pod가 호스트 네트워킹을 사용한다면(hostNetwork: true) 건너뛰어져요.- IPC sysctl(
kernel.sem,kernel.msg*,kernel.shm*,fs.mqueue.*)은 Pod가 호스트 IPC를 사용한다면(hostIPC: true) 건너뛰어져요. user.*sysctl은 Pod가 호스트 사용자 네임스페이스를 공유한다면(hostUsers: true또는 미설정) 건너뛰어져요.- UTS sysctl(
kernel.domainname)은 Pod가 호스트 네트워킹을 사용한다면(hostNetwork: true) 건너뛰어져요.
검증과 제한 (Validation and Limitations)
kubelet은 시작 중에 defaultPodSysctls를 검증해요. 네임스페이스되지 않은 sysctl, 잘못된 sysctl 이름, 또는 중복 키는 kubelet이 시작하지 못하게 해요.
또한 일부 net.* sysctl은 커널 버전에 따라 네임스페이스되지 않을 수 있어요. defaultPodSysctls에 네임스페이스되지 않은 net.* sysctl을 지정하면 Pod 샌드박스 생성이 FailedCreatePodSandBox 오류로 실패해요. Pod는 샌드박스 생성을 계속 재시도할 거예요. 지정한 모든 sysctl이 노드 커널에서 네임스페이스되는지 확인하세요.
defaultPodSysctls의 변경은 새로 생성된 Pod에만 적용돼요. kubelet은 기존 Pod를 동적으로 재구성하지 않아요(노드 재시작 후 어떻게 되는지 참고). 기존 Pod는 샌드박스가 생성될 때 적용된 sysctl로 계속 실행돼요. 기존 Pod가 업데이트된 기본 sysctl을 채택하게 하려면 그 Pod를 재생성해야 해요(예: 노드를 cordon하고 drain해서).