본문 바로가기

직접 만든 소프트웨어, 두 가지 개발 기록

구현 구조와 적용 범위, 확인한 기능과 남은 한계를 함께 기록합니다.

소프트웨어개발

Kubernetes Service 연결 안 될 때: selector·EndpointSlice·targetPort·DNS 점검

by 아빠띠띠뽀 2026. 10. 5.

클라이언트에서 Service와 대상 컨테이너로 이어지는 경로를 점검하는 Kubernetes 네트워크 개념 일러스트
AI로 직접 제작한 개념 일러스트입니다. Service의 선택 대상·엔드포인트·포트·이름 해석을 차례로 분리해 확인하는 흐름입니다.

Pod는 Running인데 Kubernetes Service로 접속하면 연결이 거부되거나 시간이 초과되나요? Service의 selector, EndpointSlice, 애플리케이션이 실제로 듣는 포트, DNS와 네트워크 정책을 순서대로 확인하면 원인을 좁힐 수 있습니다. 이 글은 selector로 Pod를 선택하는 일반적인 ClusterIP Service를 기준으로 설명합니다. ExternalName이나 selector가 없는 Service는 엔드포인트를 다루는 방식이 다르므로 같은 절차를 그대로 적용하지 마세요.

1. 어느 클러스터·네임스페이스·주소에 접속하는지 확인

먼저 현재 context와 Service의 네임스페이스를 확인합니다. 동일한 이름의 Service가 다른 네임스페이스에 있으면 짧은 이름으로 접속한 결과가 달라질 수 있습니다. 다음은 demo 네임스페이스의 web Service를 조사하는 가상 예시입니다. demo와 web은 실제 이름으로 바꾸고, 권한이 있는 조회 범위에서 실행하세요.

kubectl config current-context
kubectl -n demo get svc web -o yaml
kubectl -n demo get pods -o wide --show-labels
kubectl -n demo get endpointslices -l kubernetes.io/service-name=web -o yaml
클라이언트에서 본 결과 먼저 분리할 단계 주의할 해석
이름을 찾을 수 없음 네임스페이스·검색 도메인·DNS Service 이름과 DNS 경로부터 확인
Connection refused 선택된 대상·포트·리스닝 상태 잘못된 포트와 엔드포인트 부재 등 구분
Connection timed out 정책·라우팅·응답 경로 한 가지 원인으로 단정하지 않기
HTTP 응답은 왔지만 4xx·5xx 앱·인증·요청 경로 연결 수립과 정상 업무 응답을 구분
일부 요청만 실패 각 엔드포인트의 상태·포트 모든 대상이 같은 설정인지 비교
port-forward만 성공 로컬 포워딩과 Service 경로 ClusterIP 경로 전체의 증거는 아님

Kubernetes Service 디버깅 안내에 따라 Service 설정과 선택된 대상, 직접 접속 결과를 구분해 기록하세요. 실패한 클라이언트 위치와 오류 문구도 필요합니다. 노트북에서 수행한 테스트와 클러스터 안의 Pod에서 수행한 테스트는 경로가 같지 않을 수 있습니다. 비교 시험은 가능한 한 같은 클라이언트에서 해야 변수를 줄일 수 있습니다.

2. selector·EndpointSlice·Ready 상태 대조

Service 공식 문서를 기준으로 spec.selector가 실제 Pod 레이블과 맞는지 확인합니다. app: web을 선택하는 Service인데 Pod의 레이블이 app: frontend라면 기대한 대상이 선택되지 않습니다. 이름이 비슷하다는 사실보다 키와 값이 일치하는지가 중요합니다. selector 기반 Service에서는 같은 네임스페이스의 대상 Pod를 확인하세요.

EndpointSlice 조회 결과에서 대상 IP, 포트와 conditions를 함께 봅니다. EndpointSlice 문서에 따르면 엔드포인트에는 준비·서비스 제공·종료 상태를 나타내는 조건이 있습니다. 목록에 IP가 있다고 항상 정상 트래픽 대상이라고 단정할 수 없습니다. publishNotReadyAddresses 같은 예외 설정도 있으므로 Service 설정과 조건을 함께 읽어야 합니다. 조회 결과가 여러 Slice에 나뉠 수 있다는 점도 확인하세요.

Pod의 Running은 애플리케이션이 요청을 받을 준비가 됐다는 보장이 아닙니다. Pod 프로브 문서에 따라 readiness 상태와 실패 이유를 확인하세요. 대상 Pod가 아직 배치되지 않았다면 Pod Pending·FailedScheduling 진단 글을, 컨테이너가 반복 종료된다면 CrashLoopBackOff 진단 글을 먼저 적용하는 편이 좋습니다. Service 설정만 바꾸어 Pod의 준비 문제를 가리는 것은 원인 해결이 아닙니다.

3. port·targetPort·실제 리스닝 포트 구분

클라이언트가 연결하는 Service의 port와 Pod에서 요청을 받는 targetPort는 다를 수 있습니다. 예를 들어 Service의 80번 포트로 받은 요청을 앱의 8080번 포트에 전달할 수 있습니다. Pod의 containerPort 선언만 바꾸어도 앱 프로세스가 그 포트에서 듣기 시작하는 것은 아닙니다. 앱 시작 옵션과 로그, 실제 응답을 확인해야 합니다.

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: demo
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080

이 YAML은 필드 관계를 설명하는 예시이며 실제 클러스터에 적용하라는 파일이 아닙니다. targetPort가 숫자 대신 이름이면 선택된 Pod의 포트 이름과 대응되는지 확인합니다. 앱이 127.0.0.1에만 바인딩되어 다른 Pod에서 접근할 수 없는 경우도 있으므로 실제 리스닝 주소를 살펴보세요. 포트가 맞아도 HTTP·HTTPS 같은 애플리케이션 프로토콜을 잘못 선택하면 응답이 실패할 수 있습니다.

4. 같은 클라이언트에서 DNS와 직접 접속 나누어 시험

이미 운영 절차에 따라 사용할 수 있는 진단 Pod가 있다면 그 안에서 이름 해석과 접속을 확인합니다. 다음의 CLIENT_POD_NAME은 실제 Pod 이름으로 바꾸어야 하며 nslookup과 curl이 설치된 환경을 가정합니다. 도구가 없다는 오류는 곧바로 Service 실패의 증거가 아닙니다. 별도 진단 Pod 생성은 이미지와 권한을 검토한 뒤 해당 클러스터 절차에 따라 수행하세요.

kubectl -n demo exec CLIENT_POD_NAME -- nslookup web.demo.svc.cluster.local
kubectl -n demo exec CLIENT_POD_NAME -- curl --connect-timeout 3 --max-time 5 http://web.demo.svc.cluster.local:80

cluster.local은 흔한 예시이며 클러스터 도메인이 다르면 실제 DNS 이름으로 바꿉니다. 클러스터 DNS 디버깅 문서와 클라이언트의 DNS 설정을 비교하세요. 이어 같은 클라이언트에서 Service의 실제 ClusterIP:port와 EndpointSlice에 있는 Pod IP:실제 앱 포트로 접속 결과를 비교합니다. 실제 IP를 확인한 뒤 테스트하며, 성공 여부뿐 아니라 응답 코드와 기대한 내용이 맞는지도 기록합니다.

Pod IP의 앱 포트는 응답하는데 Service 주소만 실패하면 Service 포트·엔드포인트 매핑과 클러스터의 Service 전달 경로를 더 좁혀 볼 수 있습니다. 이름으로만 실패하고 실제 ClusterIP로는 응답하면 이름 해석 경로를 우선 확인합니다. 직접 Pod 접속도 실패하면 앱의 리스닝 주소·포트와 정책·네트워크 경로를 살펴보세요. 이 비교는 범위를 줄이는 방법이며 단일 결과만으로 특정 구성 요소의 고장을 확정하지 않습니다.

5. 가상 사례와 네트워크 정책 점검

가상 환경에서 web Service는 port 80, targetPort 8080으로 설정되어 있는데 앱 시작 옵션은 9000이라고 가정해 보겠습니다. 같은 클라이언트에서 Pod IP의 9000번 포트는 기대한 응답을 주고, Service 접속은 실패합니다. EndpointSlice의 포트도 8080이라면 앱 설정과 Service 매핑이 어긋난 근거를 확보한 것입니다. 서비스 설계상 정한 포트에 맞추어 원본 배포 설정을 수정한 뒤 엔드포인트와 클라이언트 응답을 다시 검증합니다. 아무 포트나 바꾸며 성공한 설정을 채택하는 방식은 피하세요.

NetworkPolicy 문서를 기준으로 출발 Pod의 egress와 목적 Pod의 ingress를 함께 확인합니다. 연결에 적용되는 정책은 네임스페이스와 Pod 선택 조건에 따라 달라집니다. DNS를 사용하는 테스트라면 DNS 질의에 필요한 경로도 살펴보세요. 전체 정책을 삭제해서 연결되는지 보는 방식보다 필요한 출발지·목적지·포트를 좁혀 판단하는 편이 좋습니다. Service 전달 방식과 CNI 구현에 따라 추가 확인이 필요하면 클러스터 운영자와 경로를 추적하세요.

점검 기록에는 ① context·네임스페이스, ② 실패한 클라이언트, ③ Service selector, ④ Pod 레이블·Ready 상태, ⑤ EndpointSlice의 IP·포트·조건, ⑥ 앱 리스닝 주소·포트, ⑦ DNS·ClusterIP·Pod IP 결과, ⑧ 적용 정책을 남기세요. 같은 형식으로 기록하면 변경 전후의 차이를 확인하기 쉽고, 다음 담당자에게 단순히 “Service가 안 됨”보다 구체적인 정보를 전달할 수 있습니다.

6. 자주 묻는 질문

Pod가 Running이면 Service가 반드시 연결되나요?
Running과 Ready, 실제 앱 리스닝 상태는 다릅니다. 레이블 선택과 엔드포인트의 준비 조건, 포트 매핑도 함께 확인해야 합니다.

EndpointSlice에 IP가 있으면 문제가 없나요?
IP 존재뿐 아니라 포트와 조건, Service의 예외 설정을 확인하세요. 실제 앱이 해당 주소와 포트에서 요청을 받을 수 있는지도 필요합니다.

kubectl port-forward가 성공하면 Service는 정상인가요?
포워딩으로 앱 응답을 확인하는 것은 유용하지만 ClusterIP·DNS·Pod 간 정책 경로 전체가 정상이라는 증거는 아닙니다. 문제가 난 클라이언트 위치에서 별도로 검증하세요.

자료 확인: 2026년 10월 4일. 이름·포트·명령은 설명을 위한 가상 예시이며 실제 사용자 클러스터의 점검 결과가 아닙니다. 사용 중인 Kubernetes 버전과 CNI, Service 유형에 맞는 공식 문서와 운영 절차를 확인하세요.