Kubernetes Engine 성능 튜닝 가이드
개요
Samsung Cloud Platform Kubernetes Engine(이하 SKE)의 노드 OS는 기본적으로 Samsung Cloud Platform에서 제공하는 표준 OS 이미지로 구성되며, 쿠버네티스 운영 환경에서 권장하는 OS 매개변수가 사전에 설정되어 있습니다.
kernel.pid_max=4194304
net.core.somaxconn=16384
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.forwarding=1
net.ipv4.conf.all.route_localnet=1
net.ipv4.conf.default.forwarding=1kernel.pid_max=4194304
net.core.somaxconn=16384
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.forwarding=1
net.ipv4.conf.all.route_localnet=1
net.ipv4.conf.default.forwarding=1위 설정은 노드의 호스트 network namespace에 적용됩니다. net.* 매개변수는 대부분 network namespace 단위로 격리되므로, 이 값이 애플리케이션 파드에 그대로 적용되는 것은 아닙니다. 자세한 내용은 sysctl 적용 범위를 참고하세요.
리눅스 OS에 특정 성능 최적화 요구 사항이 있는 경우, SKE에서 일부 클러스터 컴포넌트의 기본 설정을 변경할 수 있습니다.
sysctl 적용 범위
sysctl 매개변수를 변경하기 전에, 해당 항목이 network namespace 단위로 격리되는지 여부를 반드시 확인해야 합니다. 격리 여부에 따라 설정을 적용할 위치(노드 또는 파드)와 적용 방법이 달라집니다.
namespaced sysctl: 파드마다 독립적으로 설정할 수 있는 항목으로, net.* 매개변수 대부분이 여기에 해당합니다. 파드는 자신만의 network namespace를 사용하므로, 노드에서 값을 변경해도 파드로 전파되지 않습니다. 파드에 적용하려면 파드 단위로 설정해야 합니다.
unnamespaced sysctl(노드 레벨): 노드 전체에 하나의 값만 존재하는 항목입니다. net.netfilter.nf_conntrack_max처럼 파드별로 다르게 설정할 수 없으며, 노드에서 직접 변경해야 합니다.
쿠버네티스는 namespaced sysctl을 다시 safe와 unsafe로 구분하며, 구분에 따라 적용 방법이 달라집니다.
| 구분 | 대표 항목 | 적용 방법 |
|---|---|---|
| namespaced / safe | net.ipv4.ip_local_port_range, net.ipv4.tcp_syncookies, net.ipv4.tcp_keepalive_time, net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_probes | 파드의 securityContext.sysctls 필드로 특권 없이 설정 |
| namespaced / unsafe | net.core.somaxconn, net.ipv4.tcp_max_syn_backlog | 특권(privileged) initContainer로 파드마다 설정 |
| unnamespaced | net.netfilter.nf_conntrack_max | 노드에서 데몬셋 또는 사용자 정의 이미지로 설정 |
safe 목록은 쿠버네티스 버전에 따라 확장되어 왔습니다. net.ipv4.tcp_keepalive_* 항목은 쿠버네티스 1.29부터 safe 목록에 포함되었으므로, 그보다 낮은 버전의 클러스터에서는 unsafe 항목과 동일한 방법으로 설정해야 합니다.
unsafe 항목을 securityContext.sysctls로 설정하려면 kubelet의 --allowed-unsafe-sysctls 옵션으로 해당 항목을 허용해야 합니다. 다만 SKE는 관리형 서비스로 kubelet 옵션을 변경할 수 없으므로, unsafe 항목은 특권 initContainer를 사용해 설정하세요.
net.core.somaxconn은 namespaced이면서 unsafe인 항목입니다. 따라서 노드의 값을 더 높게 올려도 애플리케이션 파드에는 전파되지 않습니다. 파드의 network namespace는 생성 시 커널 상수 SOMAXCONN 값(커널 5.4 이상에서 4096)으로 초기화됩니다. 애플리케이션 파드의 Backlog를 조정하려면 파드 성능 최적화의 방법을 사용하세요.사용자 정의 노드 구성 방법
운영 체제(OS) 사용자 정의
SKE는 클러스터 버전별로 지원하는 운영 체제 목록을 제공하며, 하나의 클러스터에는 서로 다른 운영 체제를 혼용할 수도 있습니다. 지원 운영 체제와 클러스터 버전 조합은 Kubernetes Engine 사용자 가이드에서 확인하세요. 노드를 최적화하려면 다음 방법을 사용하세요.
사용자 정의 이미지(Custom Image) 생성: 이미지나 쿠버네티스 버전에 대한 보안 패치 같은 노드 업데이트는 Samsung Cloud Platform에서 제공합니다. 이 외에 고객 환경에 별도 구성이 필요한 경우, 노드용 사용자 정의 이미지를 생성하면 설정을 영구적으로 적용할 수 있습니다.
Virtual Server 메뉴에서 사용자의 Custom Image를 이용한 노드 풀을 생성할 수 있습니다. Custom Image를 이용한 노드 풀을 생성하려면 다음 절차를 참고하세요.
- SKE 이미지가 포함된 Virtual Server를 생성하세요.
- 해당 Virtual Server의 Custom Image 기능을 이용하여 이미지 등록을 진행하세요.
- 등록한 Custom Image를 선택하여 노드 풀을 생성하세요.
사용자 정의 이미지는 노드 부팅 시점에 설정이 적용되므로, 애플리케이션 파드보다 항상 먼저 반영된다는 장점이 있습니다. 노드 레벨 설정을 안정적으로 적용해야 한다면 데몬셋보다 사용자 정의 이미지를 우선 검토하세요.
임시 수정
파드에 접속하거나 다른 프로세스를 통해 노드 설정을 수정하면 해당 변경 사항은 일시적으로만 적용됩니다. 노드 자동 복구, 재시작, 업데이트, 교체와 같은 노드 작업이 발생하면 모든 변경 사항이 기본 설정으로 되돌아갑니다.
데몬셋을 활용한 자동 재적용
노드 수명 주기 작업 전반에 걸쳐 설정이 유지되도록 하려면, 초기화 컨테이너(initContainer)를 사용하는 데몬셋(DaemonSet)을 생성하세요. 데몬셋은 노드가 추가되거나 재부팅될 때마다 파드를 다시 시작하며, 그때 initContainer가 설정을 다시 적용합니다. 자세한 방법은 성능 최적화를 위한 노드 설정 수정에서 설명합니다.
성능 최적화를 위한 노드 설정 수정
노드 커널 네트워크 설정 수정
성능 최적화 요구 사항이 있는 경우, 노드에서 리눅스 커널의 sysctl 매개변수에 대한 기본 설정을 변경할 수 있습니다. 노드는 기본적으로 최적화된 커널 성능으로 자동 프로비저닝됩니다. 다만 초기화 컨테이너(initContainer)를 포함한 사용자 정의 데몬셋(DaemonSet)을 적용하면 기본 설정을 변경할 수 있습니다. 데몬셋을 적용하면 기존 노드의 설정이 모두 수정되고, 이후 새로 추가되는 노드에도 동일한 설정이 적용됩니다.
이 절의 데몬셋은 hostNetwork: true로 동작하므로 노드의 호스트 network namespace에만 설정을 적용합니다. 호스트에서 직접 동작하는 프로세스와 hostNetwork 파드에는 효과가 있지만, 자체 network namespace를 사용하는 일반 애플리케이션 파드에는 적용되지 않습니다. 애플리케이션 파드를 튜닝하려면 파드 성능 최적화를 참고하세요.
또한 데몬셋은 taint를 허용(toleration)하도록 설정하지 않으면 taint가 지정된 노드 풀에 배치되지 않습니다. 클러스터의 모든 노드를 대상으로 하려면 워크로드의 taint 구성을 함께 확인하세요.
예시 상황: TCP 통신 Backlog 부족 현상
netstat 명령으로 OS의 TCP 통신 Backlog 부족 현상이 발생하고 있는지 확인할 수 있습니다. 애플리케이션 응답 지연이나 비정상적인 접속 끊김이 발생한다면 반드시 확인해야 하는 지표입니다.
netstat -s | grep -E -i "overflow|drop"
TcpExt:
...
1380 times the listen queue of a socket overflowed
1380 SYNs to LISTEN sockets droppednetstat -s | grep -E -i "overflow|drop"
TcpExt:
...
1380 times the listen queue of a socket overflowed
1380 SYNs to LISTEN sockets dropped리스닝 소켓별로 현재 Backlog 사용량을 확인하려면 ss 명령을 사용하세요. Recv-Q는 accept를 기다리는 커넥션 수이고, Send-Q는 해당 소켓에 설정된 Backlog 크기입니다. 두 값이 비슷해지면 Backlog가 포화 상태에 가까운 것입니다.
ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:*ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:*Backlog 부족 현상은 sysctl 매개변수인 net.core.somaxconn, net.ipv4.tcp_max_syn_backlog 값을 조정하여 해결할 수 있습니다.
두 매개변수의 특징은 다음과 같습니다.
net.ipv4.tcp_max_syn_backlog: 클라이언트가 서버에 접속할 때 첫 단계인 SYN 패킷 정보를 저장하는 최대 SYN Backlog 크기입니다. net.core.somaxconn 값을 증가시키려면 tcp_max_syn_backlog 값도 함께 증가시켜야 합니다.
net.core.somaxconn: 소켓(Socket)당 허용하는 최대 Listen Backlog 값입니다. Listen Backlog는 3-way handshake를 마친 후 애플리케이션과의 연결이 완료(accept)되기 전까지 커넥션 정보를 저장하고 대기하는 큐입니다. 동시 접속 커넥션 수가 적으면 Backlog 크기가 작아도 문제가 없지만, 애플리케이션 지연으로 대기 커넥션 수가 Backlog 크기보다 커지면 나머지 커넥션은 OS에서 거부(Drop)됩니다.
net.core.somaxconn과 net.ipv4.tcp_max_syn_backlog은 모두 network namespace 단위로 격리되는(namespaced) 항목이지만 쿠버네티스 safe 목록에는 없는 unsafe sysctl이므로, 특권(privileged) 파드를 통해서만 직접 적용할 수 있습니다.
호스트 network namespace의 net.core.somaxconn 값을 조정하려면 다음 내용으로 YAML 파일을 저장하세요. spec.template.spec.initContainers 섹션에 조정하려는 sysctl 매개변수의 필드와 값을 추가하세요.
다음 예시 데몬셋은 허용되는 기본 최대 연결 수인 net.core.somaxconn을 변경합니다. 앞에서 설명한 것처럼 net.core.somaxconn을 올릴 때는 net.ipv4.tcp_max_syn_backlog도 함께 올려야 하므로, 실제 적용 시에는 initContainer의 command에 sysctl -w net.ipv4.tcp_max_syn_backlog=<값>을 같은 방식으로 추가하세요.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-tuning
namespace: kube-system
labels:
app: node-tuning
spec:
selector:
matchLabels:
name: node-tuning
template:
metadata:
labels:
name: node-tuning
spec:
hostNetwork: true
hostPID: true
hostIPC: true
initContainers:
- command:
- sh
- -c
- sysctl -w net.core.somaxconn=32768;
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl
resources: {}
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
volumeMounts:
- name: modifysys
mountPath: /sys
containers:
- resources:
requests:
cpu: 0.01
image: alpine:3.24
name: sleepforever
command:
- sleep
- infinity
volumes:
- name: modifysys
hostPath:
path: /sysapiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-tuning
namespace: kube-system
labels:
app: node-tuning
spec:
selector:
matchLabels:
name: node-tuning
template:
metadata:
labels:
name: node-tuning
spec:
hostNetwork: true
hostPID: true
hostIPC: true
initContainers:
- command:
- sh
- -c
- sysctl -w net.core.somaxconn=32768;
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl
resources: {}
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
volumeMounts:
- name: modifysys
mountPath: /sys
containers:
- resources:
requests:
cpu: 0.01
image: alpine:3.24
name: sleepforever
command:
- sleep
- infinity
volumes:
- name: modifysys
hostPath:
path: /sys노드에 데몬셋을 적용하세요.
kubectl apply -f node-tuning.yamlkubectl apply -f node-tuning.yaml노드 sysctl 매개변수를 기본값으로 되돌리려면 다음 절차를 진행하세요.
- 데몬셋을 삭제하세요. 데몬셋 파드가 제거되어 이후 추가되는 노드에는 설정이 다시 적용되지 않습니다. 다만 이미 적용된 노드의 sysctl 값은 삭제만으로 되돌아가지 않습니다.
kubectl delete ds node-tuning -n kube-systemkubectl delete ds node-tuning -n kube-system- 클러스터의 모든 노드를 재부팅하세요. 노드에 기본값이 적용됩니다.
파드 성능 최적화
특정 워크로드에 성능 요구 사항이 있는 경우, 파드 network namespace의 리눅스 커널 sysctl 매개변수에 대한 기본 설정을 변경할 수 있습니다. 애플리케이션 파드의 커널 설정은 노드 설정과 독립적이므로, 애플리케이션 성능을 튜닝할 때는 이 절의 방법을 사용해야 합니다.
애플리케이션 파드의 커널 설정을 최적화하려면 데몬셋, 레플리카셋(ReplicaSet), 디플로이먼트(Deployment), 스테이트풀셋(StatefulSet)처럼 파드 템플릿을 가진 오브젝트에 initContainer 패치를 추가하세요. initContainer는 애플리케이션 컨테이너와 동일한 network namespace를 공유하므로, initContainer에서 변경한 값이 해당 파드의 애플리케이션 컨테이너에 적용됩니다.
spec.template이 없으므로 아래 패치를 그대로 적용할 수 없습니다. 또한 실행 중인 파드의 initContainers 필드는 변경할 수 없습니다. 파드를 직접 수정하는 대신 상위 워크로드 오브젝트를 수정하여 파드를 재생성하세요.다음 initContainer 패치 내용을 pod-patch.yaml 파일로 저장하고, 조정하려는 sysctl 매개변수의 필드와 값을 추가하세요. 이 예시에서는 initContainer를 통해 허용되는 기본 최대 연결 수 net.core.somaxconn과 임시 포트 범위 net.ipv4.ip_local_port_range를 변경합니다.
spec:
template:
spec:
initContainers:
- command:
- sh
- -c
- sysctl -e -w net.core.somaxconn=32768; sysctl -e -w net.ipv4.ip_local_port_range="1025 65535";
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl
resources: {}
securityContext:
privileged: truespec:
template:
spec:
initContainers:
- command:
- sh
- -c
- sysctl -e -w net.core.somaxconn=32768; sysctl -e -w net.ipv4.ip_local_port_range="1025 65535";
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl
resources: {}
securityContext:
privileged: true특권 컨테이너는 Pod Security Admission의 baseline 또는 restricted 정책이 적용된 네임스페이스에서 거부됩니다. 위 패치를 적용하기 전에 대상 네임스페이스의 정책 수준을 확인하고, 필요한 경우 해당 워크로드만 예외로 허용하세요.
한편 위 예시의 두 항목 중 net.ipv4.ip_local_port_range는 쿠버네티스 safe 목록에 포함된 항목이므로, 이 값만 변경하면 되는 경우에는 특권 initContainer 없이 파드의 securityContext.sysctls 필드로 설정할 수 있습니다. 특권을 요구하지 않아 Pod Security Admission 제약을 받지 않으므로, 가능하면 이 방법을 사용하세요. 특권 initContainer는 net.core.somaxconn처럼 unsafe 항목에만 사용하세요.
디플로이먼트 등 파드 배포 오브젝트에 패치를 적용하세요. --patch 옵션은 패치 문자열을 받으므로, 파일로 저장한 패치는 --patch-file 옵션으로 지정해야 합니다.
kubectl patch deployment <deployment_name> -n <namespace> --patch-file pod-patch.yamlkubectl patch deployment <deployment_name> -n <namespace> --patch-file pod-patch.yaml패치가 적용되면 파드가 재생성됩니다. 파드 안에서 값이 실제로 반영되었는지 확인하세요.
kubectl exec -n <namespace> <pod_name> -- sysctl net.core.somaxconn
net.core.somaxconn = 32768kubectl exec -n <namespace> <pod_name> -- sysctl net.core.somaxconn
net.core.somaxconn = 32768커널 설정에서 net.core.somaxconn 값을 변경하면 대부분의 애플리케이션은 자동으로 업데이트된 값을 사용합니다. 다만 일부 애플리케이션은 커널 값과 일치하도록 애플리케이션 코드에서 해당 값을 수동으로 변경해야 할 수도 있습니다. 예를 들어 nginx 애플리케이션이 실행 중인 파드의 성능을 조정하는 경우, nginx 애플리케이션 코드의 backlog 필드 값도 커널 설정과 일치하도록 변경해야 합니다.
네트워크 keepalive sysctl 설정 최적화
파드에 장시간 유지되는 TCP 연결이 있고 유휴 상태에서 간헐적으로 연결이 끊기는 현상이 발생한다면, 파드의 sysctl keepalive 설정을 변경하는 것이 도움이 될 수 있습니다.
유휴 연결이 끊기는 원인은 대부분 경로상의 Load Balancer, NAT, 방화벽이 일정 시간 트래픽이 없는 세션을 정리하기 때문입니다. TCP keepalive는 유휴 구간에 주기적으로 패킷을 보내 세션을 살려 두는 역할을 하므로, net.ipv4.tcp_keepalive_time 값을 경로상 장비의 idle timeout보다 작게 설정해야 효과가 있습니다. 예를 들어 Load Balancer의 idle timeout이 60초라면 tcp_keepalive_time을 그보다 짧게 잡아야 합니다.
세 매개변수의 의미는 다음과 같습니다.
net.ipv4.tcp_keepalive_time: 연결이 유휴 상태가 된 후 첫 keepalive 패킷을 보내기까지의 대기 시간(초)입니다.
net.ipv4.tcp_keepalive_intvl: keepalive 패킷에 응답이 없을 때 재전송하는 간격(초)입니다.
net.ipv4.tcp_keepalive_probes: 응답 없는 keepalive 패킷을 몇 번까지 재전송한 후 연결을 끊을지 결정하는 횟수입니다.
SO_KEEPALIVE 옵션이 활성화된 경우에만 적용됩니다. 이 옵션은 기본적으로 비활성 상태이며, 애플리케이션 또는 사용하는 커넥션 풀 라이브러리에서 명시적으로 활성화해야 합니다. sysctl만 변경하고 애플리케이션에서 keepalive를 켜지 않으면 아무 변화가 없습니다.앞서 성능 최적화를 위한 노드 설정 수정에서 설명한 것처럼 데몬셋을 사용하면 노드에 sysctl 네트워크 값을 설정할 수 있습니다. 다만 keepalive 항목은 namespaced sysctl이므로 노드의 값이 파드로 전파되지 않으며, 이미 배포되어 있는 파드에도 연결 유지 설정을 일괄 적용할 수 없다는 한계가 있습니다. 따라서 파드 단위로 설정해야 합니다.
파드마다 설정하려면 특권(privileged) initContainer를 적용할 수 있습니다. sysctl 네트워크 값을 적용하려는 애플리케이션에는 다음 예시를 참고하여 initContainer를 설정하세요.
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-sysctl
namespace: test-ns
labels:
run: test-sysctl
spec:
replicas: 2
selector:
matchLabels:
run: test-sysctl
template:
metadata:
labels:
run: test-sysctl
spec:
initContainers:
- command:
- sh
- -c
- sysctl -e -w net.ipv4.tcp_keepalive_time=40; sysctl -e -w net.ipv4.tcp_keepalive_intvl=15; sysctl -e -w net.ipv4.tcp_keepalive_probes=6;
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl-init
resources: {}
securityContext:
privileged: true
containers:
- name: test-sysctl
image: alpine:3.24
command:
- sleep
- infinityapiVersion: apps/v1
kind: Deployment
metadata:
name: test-sysctl
namespace: test-ns
labels:
run: test-sysctl
spec:
replicas: 2
selector:
matchLabels:
run: test-sysctl
template:
metadata:
labels:
run: test-sysctl
spec:
initContainers:
- command:
- sh
- -c
- sysctl -e -w net.ipv4.tcp_keepalive_time=40; sysctl -e -w net.ipv4.tcp_keepalive_intvl=15; sysctl -e -w net.ipv4.tcp_keepalive_probes=6;
image: alpine:3.24
imagePullPolicy: IfNotPresent
name: sysctl-init
resources: {}
securityContext:
privileged: true
containers:
- name: test-sysctl
image: alpine:3.24
command:
- sleep
- infinitynet.ipv4.tcp_keepalive_time, net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_probes는 쿠버네티스 1.29부터 safe 목록에 포함되었습니다. 클러스터 버전이 1.29 이상이라면 위와 같은 특권 initContainer 대신 파드의 securityContext.sysctls 필드에 세 항목을 선언하는 방법을 권장합니다. 특권 없이 적용되므로 Pod Security Admission의 baseline 또는 restricted 정책이 적용된 네임스페이스에서도 사용할 수 있습니다.
예시의 값(40초, 15초, 6회)은 idle timeout이 60초 내외인 환경을 가정한 것입니다. 실제 값은 경로상 장비의 idle timeout과 애플리케이션의 연결 특성에 맞추어 조정하세요.

