WEB BE Repository/kubernetes, k8s

[쿠버네티스 튜토리얼] 3. 서비스 노출: ClusterIP, NodePort, Ingress

조금씩 차근차근 2025. 12. 19. 00:52

Kubernetes에서 Service(서비스) 객체는 Pod들의 논리적인 집합에 단일 접근 포인트(IP 및 DNS 이름)을 제공하는 역할을 한다.
앞서 Deployment로 Nginx Pod 여러 개를 띄웠다면, 클라이언트가 그중 어떤 Pod에 접속해야 할지 알기 어렵다.
Service를 사용하면 여러 Pod들을 하나의 서비스로 묶고, 부하 분산(Load Balancing)서비스 디스커버리(DNS)를 제공할 수 있다.

 

Kubernetes에는 몇 가지 서비스 유형(Service Types)이 있다.

  • ClusterIP (기본값)
    • 클러스터 내부에서만 접근 가능한 가상 IP를 부여한다.
    • 내부 서비스 용도로 사용된다.
  • NodePort
    • 각 Node의 IP에서 정해진 포트를 열어, 외부에서 노드IP:포트로 접근할 수 있게 한다.
  • LoadBalancer
    • 클라우드 환경의 L4 로드밸런서를 프로비저닝하여 외부 IP를 할당한다.
    • on-prem 환경에서는 ServiceLB같은 로드밸런서 컨트롤러가 필요하며, k3s는 기본적으로 ServiceLB를 내장하여 지원한다.
  • ExternalName
    • 서비스에 ClusterIP를 만들지 않고, DNS 이름 별칭만 제공하여 쿠버네티스 외부 서비스를 지칭할 때 쓴다 (특수한 경우).

추가로, HTTP/HTTPS 등의 L7 경로 기반 라우팅을 위해 Ingress라는 리소스를 사용한다.
Ingress는 여러 서비스들을 한 곳으로 모아 도메인/경로 기반으로 분기시켜주는 진입점이다.
Ingress 리소스는 자체로 동작하지 않고, Ingress Controller(예: Nginx Ingress, Traefik 등)가 클러스터에 설치되어야 동작한다.
k3s는 Traefik Ingress Controller를 기본 내장하고 있어서, 별도 설정 없이 Ingress 리소스를 바로 사용할 수 있다.

 

이번 섹션에서는 ClusterIP, NodePort, Ingress 각각을 실습해보자.

 

우선 Deployment로 실행 중인 Nginx Pod들을 대상으로 서비스를 생성해볼 것이다
(Deployment 섹션의 hello-deployment 또는 새로 Deployment를 만들어 사용).

ClusterIP 서비스 만들기

ClusterIP Service 매니페스트 작성

hello-svc.yaml 파일을 생성한다.

  • selector는 이 서비스가 트래픽을 보낼 Pod들을 선택하는 라벨이다.
    • app: hello 레이블을 가진 Pod들이 대상이 된다 (이전에 Deployment에 지정했던 라벨).
  • port: 80은 서비스 자체의 포트 번호이다. (ClusterIP 가상 IP에 연결된 포트)
  • targetPort: 80은 대상 Pod에서 열고 있는 포트 번호이다.
    • 여기서는 Nginx 컨테이너의 80포트로 트래픽을 전달한다는 의미이다.
    • 숫자 외에 컨테이너 포트 명을 쓸 수도 있지만 여기선 숫자로
  • type: ClusterIP은 기본값으로, 명시하지 않아도 ClusterIP로 생성된다. 클러스터 내부에서만 접근 가능한 IP를 하나 배정받는다.

적용 및 확인

  • CLUSTER-IP로 10.96.203.120 같은 IP가 부여된 것을 볼 수 있다. 이것은 가상 IP로, 클러스터 내부에서 이 IP로 접근하면 자동으로 hello-service로 연결된다.
  • EXTERNAL-IP는 ClusterIP 타입이므로 <none> (외부 IP 없음)이다.

이제 hello-service를 통해 Pod들에 접근해보자.

서비스 통신 확인 (클러스터 내부)

ClusterIP 서비스는 클러스터 내 Pod 또는 노드에서 접근 가능하다.
먼저 실습을 위해 클러스터 내부에 테스트용 Pod를 하나 띄워보자.

  • 위 명령은 busybox:1.34 이미지를 실행한 임시 Pod에 쉘로 접속한다.
    • (종료 시 --rm에 의해 Pod 삭제)
  • Busybox 쉘 내에서 하단의 명령어를 입력하면 위의 HTML 출력이 나온다.

  • hello-service라는 DNS 이름으로 서비스에 접근하고 있다.
  • Kubernetes는 서비스 생성 시 <서비스명>.<네임스페이스>.svc.cluster.local이라는 DNS 이름을 할당하며, 같은 네임스페이스에서는 간략히 http://hello-service로 접근 가능하다.

결과로 Nginx의 기본 페이지 HTML이 출력되면 서비스 통해 Nginx Pod들과 통신이 잘 된다.

여러 번 실행해보면 wget 결과가 3개의 Pod 중 어느 것으로 가는지 알 수는 없지만, Service가 알아서 라운드로빈으로 트래픽 분배를 수행한다.

 

참고: Kubernetes DNS는 CoreDNS가 제공하며, 서비스 이름을 resolution해준다.
DNS 설정은 각 Pod의 /etc/resolv.conf에 자동 구성되어, <서비스명>이나 <서비스명>.<네임스페이스> 등을 찾을 수 있게 해준다(예: hello-service.default.svc.cluster.local).

ClusterIP 타입은 클러스터 외부에서는 접근할 수 없기 때문에, 일반 사용자가 이용하는 웹서비스 등을 만들려면 NodePort나 Ingress를 추가로 설정해야 한다.

 

다음으로 NodePort를 설정해보자.

NodePort 서비스로 외부에 노출하기

NodePort 타입은 Service에 노출용 포트를 할당하여 각 Kubernetes 노드의 IP:포트로 서비스를 이용할 수 있게 해준다.
로컬 환경(k3s 단일 노드 등)에서는 NodePort를 이용하면 곧바로 그 노드(혹은 PC)의 IP에서 포트로 접근이 가능하므로 편리하다.

NodePort로 수정

앞서 만든 hello-service를 NodePort로 변경해보자.
kubectl patch도 사용 가능하지만, 여기에서는 YAML을 새로 작성해 apply 할 것이다.

  • type: NodePort로 지정했다.
  • nodePort: 30080을 지정하여 고정 포트를 요청했다.
    • (30000~32767 범위 내에서 지정 가능하며, 미지정 시 자동 할당)
  • port: 80, targetPort: 80은 이전과 동일하다.

적용

PORT(S) 항목이 80:30080/TCP로 표시되는데, 이는 서비스포트 80이 NodePort 30080으로 매핑되었음을 뜻한다.

접근 테스트

NodePort는 클러스터의 각 노드에서 해당 포트를 listening한다. 단일 노드 k3s라면 그 노드 = 호스트 머신이 된다.

  • 웹 브라우저로 http://localhost:30080에 접속해도 nginx 환영 페이지가 떠야 한다.
  • NodePort를 통해 외부에서도 Pod에 연결된 것을 확인했다.

NodePort 방식은 간단하지만, 포트 번호가 30000번대로 노출되고, 여러 서비스가 있을 경우 포트 관리가 번거로울 수 있다.
또한 HTTP/HTTPS 서비스를 여러 개 운영 시 각기 다른 포트를 사용해야 하므로 사용자 접근성이 떨어진다.

 

 

이 문제를 해결하기 위해 Ingress를 사용한다.

Ingress로 HTTP 경로 기반 라우팅하기

Ingress는 하나의 진입점(URL)으로 다수의 서비스들을 라우팅하거나, 도메인명을 기반으로 가상 호스트를 구현할 때 사용된다.
예를 들어 example.com/app1 -> 서비스 A, example.com/app2 -> 서비스 B 식으로 구성 가능하다.

 

Ingress를 사용하려면 Ingress Controller가 필수인데, k3s는 Traefik을 기본 Ingress Controller로 포함하고 있어 바로 사용할 수 있다.

Traefik이 k3s에서 자동 설치되어 traefik이라는 Pod가 kube-system 네임스페이스에서 동작 중일 것이다.

Traefik Ingress (k3s 기본값): Traefik은 포트 80과 443으로 ingress 진입점을 개방하며, Ingress 리소스를 감시하여 규칙을 만든다.
k3s의 Traefik은 Service 타입이 LoadBalancer로 설정되어 각 노드 80/443 포트를 활용한다.
(실제로 NodePort로 동작하고 Traefik이 그 NodePort를 바인딩하여 사용하는 구조)

 

따라서 k3s에서 Ingress 리소스를 만들면, 기본적으로 노드의 80/443 포트로 접속하는 HTTP/HTTPS 트래픽을 Traefik이 받아서 처리한다.

주의: Traefik 사용 중에는 80/443 포트를 다른 용도로 NodePort/HostPort에 쓰지 못한다.

Ingress 리소스 생성

hello-ingress.yaml 파일을 만들자.

  • rules 아래에 호스트와 경로 규칙을 정의한다.
    • 여기서는 hello.local 도메인으로 들어오는 / 경로 요청을 hello-service:80으로 보낸다는 의미다.
  • pathType: Prefix는 경로 접두사 일치 방식을 나타낸다. (기본값)
    • 즉, http://hello.local/ 로 오는 요청을 모두 hello-service 서비스로 라우팅한다.
    • 필요에 따라 여러 paths 항목을 넣어 서로 다른 path를 다른 서비스로 보낼 수 있다.
    • 또한 rules를 여러개 두어 host 별로 다르게 구성할 수도 있다.
    • 여기서는 간단히 하나의 host에 매핑했다.

Ingress 리소스 추가 고려사항 - 멀티 노드 구성

  • Ingress는 L7 라우팅 규칙을 정의하는 Kubernetes 리소스이며, 실제 트래픽 처리는 Ingress Controller가 수행한다.
  • Ingress Controller는 보통 클러스터 내부에서 Pod(Deployment/DaemonSet) 로 실행되며, 외부 트래픽은 Service(LoadBalancer/NodePort 등) 를 통해 유입된다.
  • Ingress를 사용하려면 DNS가 해당 host를 가리키도록 하거나, 개발 환경에서는 호스트 파일에 host명을 추가해야 한다.
  • 요청 -> etc/hosts 파일로 DNS 탐색 -> ingress controller에 도착 -> ingress controller가 적절한 파드 선택 -> 연결된 파드 -> 파드 내 컨테이너
  • hello.local은 예시 host로, 실제 DNS에 등록되지 않은 도메인이다.
  • 로컬 PC에서 테스트하려면 /etc/hosts에 127.0.0.1 hello.local (또는 노드 IP) 항목을 추가하자.

적용 및 확인

  • ADDRESS에 192.168.64.10 등이 표시되었다면 Ingress Controller(Traefik)가 할당한 IP이다.
    • k3s 기본 Traefik+ServiceLB는 모든 노드 IP를 external IP로 표시하기도 한다.
  • 즉 Ingress 진입점이 NodePort/LoadBalancer 통해 열려있는 주소다.

상세 확인

  • Traefik이 Ingress를 인식하여 hello.local -> hello-service 규칙이 설정된 것을 볼 수 있다.

접속 테스트

curl http://hello.local 을 수행해보자.

  • Traefik(Ingress Controller)이 80 포트에서 요청을 받아 hello-service로 전달하고, hello-service는 다시 Nginx Pod들 중 하나로 포워드하여 응답을 준 것이다.

Ingress를 통해 도메인 기반으로 서비스에 접근할 수 있게 되었다.
필요하면 TLS 인증서 등을 설정하여 HTTPS (hosts: hello.local, tls 필드 등) 구성을 추가할 수도 있지만 여기서는 기본 동작만 확인한다.

 

Traefik 대시보드


Traefik v2 이상에서는 기본적으로 대시보드가 비활성이다.
k3s 설정을 커스터마이즈하면 Traefik Dashboard도 띄울 수 있지만 본 튜토리얼 범위에서는 다루지 않는다.

Ingress 정리

필요 시 Ingress 리소스를 삭제한다.

요약

  • 이번 섹션에서는 Service와 Ingress를 사용한 네트워크 노출 방법을 실습했다.
  • ClusterIP 서비스: 내부에서 Pod들에게 접근 가능한 가상 IP와 DNS 이름을 제공.
    • 서비스 디스커버리, 로드밸런싱 기능 포함
  • NodePort 서비스: 클러스터 노드의 포트를 통해 외부 접근을 허용.
    • 간편하지만 포트 관리 이슈 있음.
  • Ingress: HTTP(S) 계층에서 호스트/경로 기반으로 다수 서비스 통합 노출.
    • Ingress Controller가 필요하며, k3s의 Traefik처럼 L7 프록시/로드밸런서 역할 수행.
  • k3s의 Traefik 기본 설정으로 쉽게 Ingress를 활용할 수 있음을 보았다.

배운 개념

  • 서비스의 역할(엔드포인트 추상화 및 로드밸런싱)
  • 서비스의 DNS 및 가상 IP
  • NodePort/LoadBalancer를 통한 외부 노출 원리
  • Ingress를 이용한 경로 기반 라우팅
  • Ingress Controller의 필요성