SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-10-06

Ubuntu kubelet 10250 포트 오류 해결 방법

kubeadm init 시 발생하는 address already in use 오류와 kubectl logs 및 exec 실패 원인인 10250 포트 방화벽 문제를 해결합니다. kubelet API 통신을 위한 필수 포트 설정과 프로세스 점유 확인 방법을 단계별로 안내합니다.

포트 10250의 역할

포트 10250은 kubelet API가 사용하는 포트이며, 이와 관련된 모든 오류는 두 가지 상반된 문제 중 하나입니다. 포트를 이미 다른 프로세스가 점유하고 있어 kubeadm init이 실행을 거부하거나, 반대로 아무것도 해당 포트에 접근할 수 없어 노드가 정상적으로 보여도 kubectl logs 및 kubectl exec이 실패하는 경우입니다.

kubelet은 Kubernetes가 모든 노드에서 실행하는 에이전트입니다. 이 에이전트는 컨테이너를 시작하고 그 상태를 컨트롤 플레인에 보고합니다. 또한 TCP 10250 포트에서 대기하며 컨트롤 플레인이 호출하는 HTTPS API를 제공합니다. 사용자가 kubectl logs, kubectl exec, kubectl attach 또는 kubectl port-forward 명령을 실행하면 API 서버가 해당 포트로 연결을 시도합니다. metrics-server는 동일한 포트에서 /metrics/resource를 스크래핑하며, 이것이 kubectl top node이 작동하는 원리입니다.

해당 API는 인증이 필요합니다. kubeadm은 익명 접근을 차단하고 kubelet이 클러스터 CA(인증 기관)를 참조하도록 설정하므로, 자격 증명이 없는 요청은 컨테이너 내부 셸을 여는 대신 Unauthorized 응답을 받게 됩니다. 이 세부 사항을 기억하십시오. 포트가 도달 가능한지 확인하는 가장 빠른 방법이기 때문입니다. 포트 개념이 생소하다면 Linux에서 포트의 실제 의미를 참조하십시오. 이 가이드는 해당 모델을 전제로 합니다.

두 가지 실패 유형 모두 하나의 요구 사항에서 비롯됩니다. kubelet이 시작되기 전에는 포트 10250이 비어 있어야 하며, 실행 중일 때는 컨트롤 플레인에서 접근 가능해야 합니다.

두 가지 문제 중 어떤 상황인지 확인하기

해당 노드에서 다음 명령어를 실행하십시오. 아래의 모든 명령어는 사용자가 직접 자신의 서버에서 실행하는 명령어입니다.

sudo ss -lntp | grep 10250
sudo systemctl status kubelet --no-pager

ss -lntp은 각 프로세스가 점유하고 있는 리스닝 TCP 소켓 목록을 출력합니다. -l는 리스닝 상태를 의미하며, -n은 포트 번호를 숫자로 표시하고, -t은 TCP로 범위를 제한하며, -p는 소유 프로세스를 보여줍니다. 마지막 플래그는 root 권한이 필요합니다. 권한이 없으면 프로세스 열이 비어 있어 아무런 정보도 얻을 수 없습니다.

users:(("kubelet",pid=1043,fd=23))으로 끝나는 줄이 있다면 kubelet이 실행 중이며 해당 포트를 점유하고 있다는 뜻입니다. 포트가 비어 있을 것으로 예상했다면, 이것이 바로 문제의 원인입니다. 만약 ss를 실행했는데 아무것도 출력되지 않는데도 컨트롤 플레인이 여전히 이 노드에 접근할 수 없다면, 애초에 포트를 서비스하는 프로세스가 없으므로 방화벽 문제는 아닙니다. 방화벽 규칙을 건드리기 전에 kubelet이 왜 중단되었는지 먼저 파악하십시오.

systemctl status kubelet는 상황의 나머지 절반을 보여줍니다. active (running)에서 시작 시간이 몇 분 전으로 표시되는 것은 정상입니다. kubeadm init 또는 kubeadm join을 실행하기 전에 kubelet이 몇 초마다 재시작되는 것 역시 정상입니다. 패키지 단위 서비스는 설치 시점에 시작되지만, 설정 파일이 없으면 종료되기 때문입니다. 업스트림 문서에서는 kubelet이 kubeadm의 지시를 기다리는 동안 발생하는 이러한 크래시 루프를 예상된 동작으로 정의합니다. systemd의 재시작 동작이 생소하다면 systemd 서비스 유형과 재시작 정책의 작동 방식에서 이 섹션의 배경 지식을 확인할 수 있습니다.

kubeadm init 실행 시 10250 포트가 이미 사용 중인 이유

kubeadm init은 디스크에 내용을 기록하기 전에 사전 점검을 수행합니다. 이 점검 과정에서 제어 평면(control plane)에 필요한 각 포트를 바인딩하려고 시도하며, 바인딩에 실패하면 10250 포트를 명시하며 오류를 발생시키고 중단합니다. 이는 버그가 아닙니다. 이전 클러스터의 잔재 위에 두 번째 클러스터를 구축하는 것을 kubeadm이 거부하는 것입니다.

실무에서는 다음 네 가지 원인으로 발생합니다.

  • 중간에 실패한 이전 kubeadm init 또는 kubeadm join 작업. kubelet이 이미 설정을 받아 실행 중이며 해당 포트를 점유하고 있습니다.
  • 시작은 되었으나 완료되지 않은 kubeadm reset. reset은 kubelet을 중단시키지만 유닛을 비활성화하지는 않으므로, 다음 재부팅 시 리스너가 다시 살아납니다.
  • 동일한 서버에 설치된 k3s 또는 다른 Kubernetes 배포판. k3s는 kubelet을 내장하고 있으며, 이 kubelet 또한 10250 포트를 바인딩합니다.
  • kubeadm을 아직 실행하지 않은 서버에서 apt를 통해 설치되어 자체 systemd 유닛으로 시작된 kubelet 패키지.

무언가를 변경하기 전에 다음 명령어로 원인을 파악하십시오.

sudo ss -lntp 'sport = :10250'
systemctl list-units --type=service --state=running | grep -Ei 'kubelet|k3s|k0s'

리스너가 k3s에 속해 있다면, 작업을 중단하고 실제로 운영할 클러스터를 결정하십시오. k3s와 kubeadm은 동일한 포트와 동일한 CNI(Container Network Interface) 디렉터리를 사용하므로 한 서버에서 공존할 수 없습니다. k3s 설치 프로그램은 서버 노드에는 /usr/local/bin/k3s-uninstall.sh에, 에이전트 노드에는 k3s-agent-uninstall.sh에 제거 스크립트를 남깁니다.

kubelet을 종료해도 포트가 해제되지 않는 이유

sudo pkill kubelet은 약 10초 동안 10250 포트를 해제합니다. 패키지에 포함된 유닛 파일에는 재시작 정책이 설정되어 있으므로, systemd가 새로운 kubelet을 시작하고 다시 동일한 포트를 바인딩합니다. 다음 명령어로 해당 정책을 직접 확인할 수 있습니다.

systemctl show kubelet -p Restart -p RestartSec
sudo systemctl stop kubelet
sudo ss -lntp | grep 10250

Restart=always과 RestartSec=10은 해당 유닛의 기본 설정이며, 이것이 바로 kill를 실행했을 때 일시적으로 성공한 것처럼 보이다가 다시 실패하는 이유입니다. systemctl stop은 포트를 해제하는 올바른 방법입니다. systemd는 중지하라고 명령한 유닛을 더 이상 재시작하지 않기 때문입니다.

클러스터의 절반을 담당하는 노드에서는 포트를 비우는 것만으로는 충분하지 않습니다. /var/lib/kubelet/config.yaml, /etc/kubernetes/pki 아래의 인증서, 그리고 /etc/kubernetes/manifests에 있는 모든 정적 파드 매니페스트는 여전히 남아 있습니다. 이후 수행되는 사전 점검(preflight check) 과정에서 이 파일들로 인해 오류가 발생하며, 강제로 점검을 통과시키면 인증서와 설정이 일치하지 않는 클러스터가 생성됩니다. 대신 노드를 올바르게 초기화(reset)하십시오.

노드를 깔끔하게 초기화하기

sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d
rm -rf $HOME/.kube
sudo systemctl stop kubelet
sudo ss -lntp | grep -E '10250|6443|2379'

-f 플래그는 확인 프롬프트를 생략합니다. reset은 init 또는 join이 수행한 작업을 최대한 되돌리려 시도합니다. 이 과정에서 로컬 파일과 설정을 제거하고, 컨트롤 플레인 노드의 로컬 etcd 멤버를 삭제하며, /etc/kubernetes/pki의 인증서를 정리하고, kubelet 설정과 매니페스트를 제거합니다.

문서에는 reset 후 남는 항목이 명시되어 있으며, 각 항목은 종종 문제를 일으킵니다. reset은 /etc/cni/net.d을 정리하지 않으므로, 이전 CNI 플러그인 설정이 그대로 남아 새 클러스터가 이를 읽어 들입니다. 또한 kube-proxy가 호스트에 적용한 iptables, nftables, IPVS 규칙도 정리하지 않습니다. $HOME/.kube도 건드리지 않기 때문에, kubectl은 더 이상 존재하지 않는 클러스터와 계속 통신하며 새로운 문제처럼 보이는 인증서 오류를 반환합니다.

남아 있는 패킷 규칙은 처리하기 까다롭습니다. 수동으로 테이블을 플러시하면 ufw가 설치한 규칙까지 모두 삭제되는데, Ubuntu의 ufw는 동일한 백엔드를 통해 작성되기 때문입니다. 이로 인해 sudo ufw reload을 실행하기 전까지 서버는 필터링되지 않은 상태가 됩니다. 어차피 재구축할 노드라면 reset 후 재부팅하십시오. 재부팅은 kube-proxy가 추가한 런타임 규칙을 지워주며, 반쯤 플러시된 규칙 세트를 정리하는 것보다 시간이 적게 듭니다. iptables 규칙과 nftables 규칙이 서로의 출력에 나타나는 이유에서 내부적으로 어떤 일이 일어나는지 설명합니다.

마지막으로 ss 명령을 실행했을 때 아무것도 출력되지 않아야 합니다. 10250, 6443, 2379 포트에서 리스닝 중인 프로세스가 없어야 노드가 새로운 kubeadm init을 수행할 준비가 된 것입니다.

kubectl logs 및 kubectl exec가 10250 포트에서 타임아웃되는 이유

이는 반대되는 상황에 대한 불만 사항이며, 포트 문제라고 스스로 알리지 않습니다. 클러스터는 정상적으로 시작됩니다. 노드는 Ready 상태입니다. 파드도 실행됩니다. 그러다 특정 명령 하나가 실패합니다.

Error from server: Get "https://10.0.0.12:10250/containerLogs/default/web-0/web": dial tcp 10.0.0.12:10250: i/o timeout

메시지의 끝부분부터 읽어 보십시오. API 서버가 10250 포트를 통해 노드로 TCP 연결을 시도했으나 응답을 받지 못했습니다. i/o timeout는 패킷이 아무런 응답 없이 폐기되었음을 의미하며, 이는 노드의 호스트 방화벽이나 제어판의 별도 네트워크 방화벽 등 무언가가 패킷을 차단하고 있다는 뜻입니다. 같은 위치의 connect: connection refused은 정반대의 상황을 의미합니다. 패킷은 도달했으나 수신 대기 중인 프로세스가 없으므로 kubelet이 중단된 상태입니다. 이는 connection refused 대 connection timed out에서 설명한 원인과 동일하며, 여기서는 포트 번호만 다를 뿐입니다.

노드 상태는 반대 방향으로 전달되기 때문에 이 모든 과정 중에도 노드는 Ready 상태를 유지합니다. kubelet은 6443 포트를 통해 API 서버로 아웃바운드 연결을 맺고 자신의 하트비트를 전송하며, 이는 10250 포트로 들어오는 인바운드 연결을 필요로 하지 않습니다. 따라서 10250 포트가 차단되면 클러스터는 파드를 정상적으로 스케줄링하지만 logs, exec, port-forward, metrics 명령만 실패하게 됩니다.

kubectl top node이 error: Metrics API not available에 응답하는 과정은 metrics-server를 통해 본 동일한 오류이며, 해당 로그에는 노드와 포트 정보가 명시됩니다.

unable to fully scrape metrics from node worker-1: unable to fetch metrics from node worker-1: Get "https://10.0.0.12:10250/metrics/resource": dial tcp 10.0.0.12:10250: i/o timeout

방화벽 규칙을 수정하기 전에 경로를 테스트하십시오

컨트롤 플레인 노드에서 워커 노드의 주소를 대상으로 다음 명령을 실행하십시오:

nc -zv 10.0.0.12 10250
curl -sk -o /dev/null -w '%{http_code}\n' https://10.0.0.12:10250/healthz

nc -z은 연결을 열고 닫은 뒤, 포트가 연결을 수락하면 succeeded!을 출력합니다. curl 명령줄을 사용하는 것이 더 나은 테스트 방법인데, 이는 단순히 포트가 열려 있는지를 확인하는 것이 아니라 kubelet이 실제로 서비스를 제공하고 있음을 증명하기 때문입니다. 이 명령은 401를 출력합니다. 이것이 정상적인 결과입니다. TLS(transport layer security) 핸드셰이크가 완료되었고, kubelet이 인증되지 않은 요청을 거부한 것인데, 이는 kubelet이 수행해야 할 정확한 동작입니다. -k은 인증서 확인을 건너뛰는데, 신뢰 체인이 아닌 경로를 테스트하는 것이므로 문제가 없습니다.

타임아웃으로 끝나는 긴 대기 시간은 패킷이 드롭되고 있음을 의미합니다. curl: (7) Failed to connect가 즉시 반환된다면 해당 호스트의 포트가 닫혀 있는 것입니다. 노트북이 아닌 컨트롤 플레인 노드에서 테스트하십시오. 이 환경에서 접근 권한이 중요한 유일한 머신은 컨트롤 플레인이기 때문입니다.

컨트롤 플레인과 워커 노드에 필요한 포트

다음은 업스트림에서 명시하는 인바운드 포트입니다. 컨트롤 플레인 노드에서는 API 서버를 위한 TCP 6443 포트를 kubectl를 실행하는 모든 대상에 대해 개방해야 합니다. etcd 클라이언트 및 피어 API를 위한 TCP 2379에서 2380 포트는 API 서버와 etcd 자체에서 사용합니다. kubelet API를 위한 TCP 10250 포트는 노드 자체와 컨트롤 플레인에서 사용합니다. kube-scheduler를 위한 TCP 10259 포트와 kube-controller-manager를 위한 TCP 10257 포트는 노드 자체에서만 사용합니다.

워커 노드에서는 kubelet API를 위한 TCP 10250 포트를 노드 자체와 컨트롤 플레인에서 사용합니다. kube-proxy를 위한 TCP 10256 포트는 노드 자체와 상태 확인을 수행하는 로드 밸런서에서 사용합니다. NodePort 서비스를 위한 TCP 및 UDP 30000에서 32767 포트는 기본 범위이며, 해당 서비스가 필요한 모든 대상에서 접근할 수 있어야 합니다.

사용 중인 CNI 플러그인은 위 목록 외에 고유한 포트를 추가로 사용합니다. Flannel과 Calico의 VXLAN 모드는 노드 간 UDP 4789 포트가 필요합니다. BGP를 사용하는 Calico는 TCP 179 포트가 필요합니다. 사용 중인 플러그인의 문서를 확인하여 해당 포트를 노드 간에 개방하십시오. 그렇지 않으면 이 섹션의 모든 포트를 개방하더라도 서로 다른 노드에 있는 파드 간 통신이 불가능합니다.

인터넷에 노출하지 않고 10250 포트 열기

kubelet API는 노드 내의 모든 컨테이너에서 프로세스를 시작할 수 있습니다. 10250 포트가 열려 있다는 것은 노드에 대한 root 권한이 열려 있는 것과 같으므로, 소스 주소를 기준으로 접근을 제한해야 합니다. 어떤 경우에도 외부에서 무제한으로 접근하도록 허용해서는 안 됩니다.

sudo ufw allow from 10.0.0.0/24 to any port 10250 proto tcp comment 'kubelet API'
sudo ufw allow from 10.0.0.0/24 to any port 10256 proto tcp comment 'kube-proxy'
sudo ufw status numbered

10.0.0.0/24을(를) 노드들이 공유하는 네트워크 대역으로 교체하십시오. ufw status numbered은(는) 활성화된 규칙을 인덱스와 함께 나열하므로, 잘못 설정된 규칙은 sudo ufw delete <number>을(를) 사용하여 삭제할 수 있습니다. VPS를 위한 ufw 기초에서 어떤 규칙이 실제로 적용되는지 결정하는 규칙 우선순위 설정 방법을 다룹니다.

ufw 설정 하나가 Kubernetes의 동작을 방해할 수 있습니다. 노드를 가로지르는 Pod 트래픽은 로컬로 전달되지 않고 포워딩되는데, ufw는 기본적으로 포워딩된 패킷을 차단합니다. /etc/default/ufw 파일에서 DEFAULT_FORWARD_POLICY="ACCEPT"을(를) 설정하고 sudo ufw reload을(를) 실행하십시오. 이 설정이 없으면 10250 포트가 완전히 열려 있더라도 노드 간 Pod 대 Pod 통신은 실패합니다.

사용 중인 클라우드 제공업체의 방화벽도 확인하십시오. 대부분의 VPS 관리 패널은 서버 앞단에서 동작하는 네트워크 수준의 방화벽을 제공하며, 이는 ufw status에서는 보이지 않습니다. 패킷이 서버에 도달하지 못한다면 노드에 추가한 규칙은 아무런 효과가 없습니다.

포트는 연결 가능하지만 요청이 실패하는 경우

일부 10250 오류는 응답이 지연되지 않고 즉시 반환됩니다. 이는 연결은 성공했으나 요청이 거부되었음을 의미합니다. metrics-server 로그에 나타나는 x509: certificate signed by unknown authority은 kubelet이 스크레이퍼가 신뢰하지 않는 자체 서명 인증서를 제공하고 있음을 뜻합니다. 일반적인 해결책은 kubelet 서빙 인증서 순환(serving certificate rotation)을 활성화하여 클러스터 CA가 서명하도록 한 뒤 인증서 서명 요청(CSR)을 승인하는 것입니다. 또는 테스트 클러스터라면 위험을 감수하고 --kubelet-insecure-tls 옵션을 사용하여 metrics-server를 실행할 수 있습니다.

Forbidden를 포함하는 메시지가 nodes/proxy 또는 nodes/metrics과 함께 나타난다면 이는 RBAC(역할 기반 접근 제어) 실패입니다. 호출자가 kubelet에 도달했으나, kubelet이 API 서버에 해당 ID가 하위 리소스를 사용할 권한이 있는지 확인했고 API 서버가 이를 거부한 상황입니다. 호출자의 ClusterRole을 수정하십시오. 방화벽 설정 변경은 아무런 도움이 되지 않습니다. 차단된 것이 아니기 때문입니다.

단일 소규모 클러스터만 필요한 경우

VPS 한 대에서 처음으로 kubeadm을 구성하다가 이러한 오류가 발생한다면, kubeadm이 정말 필요한지 고려해 보아야 합니다. VPS에서의 단일 노드 k3s 클러스터를 사용하면 kubelet, kube-proxy, CNI가 이미 구성된 상태로 명령 한 번에 작동하는 Kubernetes API를 얻을 수 있습니다. 포트 10250은 여전히 존재하며 동일한 규칙이 적용되지만, 더 이상 제어 평면(control plane)을 직접 구축할 필요가 없습니다.

FAQ

Kubernetes에서 포트 10250은 어떤 용도로 사용됩니까?

이 포트는 모든 노드(컨트롤 플레인 및 워커 노드)에서 kubelet이 사용하는 인증된 HTTPS API입니다. API 서버는 kubectl logs, kubectl exec, kubectl attach 및 kubectl port-forward 작업을 위해 이 포트에 연결하며, metrics-server는 kubectl top 데이터를 제공받기 위해 /metrics/resource를 수집합니다. 노드 상태 확인에는 이 포트를 사용하지 않는데, 이는 kubelet이 포트 6443을 통해 API 서버로 하트비트를 직접 전송하기 때문입니다. 따라서 포트 10250이 차단되면 노드는 Ready 상태로 표시되며, 로그 확인이나 exec 명령은 실패하게 됩니다.

포트 10250에서 리스닝 중인 프로세스를 어떻게 찾습니까?

노드에서 sudo ss -lntp | grep 10250를 실행하십시오. 줄 끝에 있는 users:((...)) 필드에 프로세스 이름과 PID가 표시됩니다. sudo 권한이 중요합니다. root 권한이 없으면 프로세스 열이 비어 있기 때문입니다. 소유자가 kubelet인 경우, sudo systemctl status kubelet --no-pager 명령을 통해 정상적으로 작동 중인지 아니면 재시작 루프에 빠져 있는지 확인할 수 있습니다. 소유자가 k3s라면 한 서버에 두 개의 Kubernetes 배포판이 설치된 것이므로 하나를 제거해야 합니다.

방화벽에서 포트 10250을 반드시 열어야 합니까?

네, 노드 간 통신을 위해 필요합니다. 컨트롤 플레인은 자기 자신을 포함한 모든 노드의 10250 포트에 접근할 수 있어야 합니다. 그렇지 않으면 로그, exec, port-forward 및 메트릭 기능이 모두 실패합니다. sudo ufw allow from 10.0.0.0/24 to any port 10250 proto tcp와 같이 노드들이 공유하는 네트워크 대역으로 접근 소스를 제한하십시오. 인터넷에 이 포트를 공개해서는 안 됩니다. 해당 포트에 인증할 수 있는 대상은 노드 내 모든 컨테이너에서 프로세스를 실행할 수 있기 때문입니다.

특정 노드의 파드에서만 kubectl logs가 실패하는 이유는 무엇입니까?

차단이 노드 단위로 발생하며, API 서버는 파드가 호스팅된 특정 노드에 직접 연결하기 때문입니다. 오류 메시지를 확인하십시오. 연결을 시도한 노드의 IP 주소가 포함되어 있습니다. 그 후 컨트롤 플레인 노드에서 nc -zv <node-ip> 10250을 실행하십시오. 타임아웃이 발생한다면 해당 노드의 방화벽이나 클라우드 제공업체의 네트워크 방화벽 문제일 가능성이 큽니다. connection refused 오류가 발생한다면 해당 노드에서 kubelet이 실행 중이지 않은 것이므로, 대신 해당 노드에서 systemctl status kubelet를 확인하십시오.