Service 로 애플리케이션 노출하기

KubernetesBeginner
지금 연습하기

소개

이전 실습에서는 Pod 가 생성되고 사라질 수 있다는 점을 배웠습니다. Pod 가 종료되고 새 Pod 로 교체되면 새 Pod 에는 완전히 다른 IP 주소가 할당됩니다. 전화를 끊을 때마다 전화번호가 바뀌는 친구에게 전화를 건다고 생각해 보세요.

Kubernetes 는 이 문제를 해결하기 위해 Service를 사용합니다.

Service 는 연결된 Pod 가 바뀌더라도 워크로드에 안정적인 네트워크 식별자를 제공합니다. Pod 의 수명 주기와 Service 엔드포인트를 분리하는 것은 Kubernetes 네트워킹의 기본 개념입니다.

이는 Kubernetes 네트워킹에서 가장 중요한 개념 모델 중 하나입니다. Pod 는 교체될 수 있어야 하지만, 클라이언트는 계속 신뢰할 수 있는 주소를 사용해야 합니다. Service 는 변경되는 Pod 앞에 위치해 안정적인 이름과 가상 IP 를 제공함으로써 이 차이를 해결합니다.

이 실습에서는 다음 작업을 수행합니다.

  • 애플리케이션에 안정적인 주소를 제공하는 Service 를 생성합니다.
  • Service 가 어떤 Pod 로 트래픽을 전달할지 지정하는 방법을 배웁니다 (Selector 사용).
  • NodePort라는 특정 유형의 Service 를 사용해 클러스터 외부에서 애플리케이션에 접속합니다.

Service YAML 생성

이 단계에서는 Service의 구성 파일을 생성합니다. 여기서는 NodePort라는 특정 유형을 사용합니다.

NodePort Service 는 클러스터의 모든 Node(서버) 에 특정 포트를 엽니다. 외부에서 들어올 수 있도록 집에 특정한 문을 하나 여는 것과 같습니다.

NodePort 는 각 노드의 포트에 직접 매핑되므로 이해하기 쉽지만, 일반적으로 퍼블릭 트래픽을 위한 최종 프로덕션 설계로 사용되지는 않습니다. 규모가 큰 환경에서는 NodePort 를 클라우드 로드 밸런서나 Ingress 계층 뒤에 배치하는 경우가 많습니다. 이 실습에서는 네트워크 경로를 초보자도 확인할 수 있다는 점에서 NodePort 를 사용합니다.

프로젝트 디렉터리에 service.yaml이라는 파일을 생성합니다.

nano service.yaml

다음 내용을 붙여넣습니다. selector 부분이 현재 app: unknown으로 되어 있는 것에 주목하세요. 이 값을 일부러 이렇게 설정해 Service 의 동작 방식을 확인합니다.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  ports:
    - port: 80 ## The port the Service exposes internally
      targetPort: 80 ## The port the container is listening on
      nodePort: 30008 ## The static door we are opening to the outside
  selector:
    app: unknown ## This needs to match your Pod's label

저장하고 종료합니다 (Ctrl+X, Y, Enter).

이 파일은 my-service라는 이름의 Service 를 정의합니다. Service 는 포트 30008(nodePort) 에서 대기합니다. 이 포트로 들어오는 모든 트래픽은 app: unknown 레이블이 지정된 Pod 로 전달됩니다. 현재는 이런 Pod 가 존재하지 않습니다.

Selector 수정

Service 는 Selector를 사용해 트래픽을 전달할 Pod 를 찾습니다. Selector 는 우편물의 주소 라벨과 같은 역할을 합니다. 봉투의 주소 (Service Selector) 가 집의 주소 (Pod Label) 와 일치하지 않으면 우편물이 도착하지 않습니다.

레이블과 Selector 는 Service 뿐 아니라 Kubernetes 전반에서 사용됩니다. 이들은 Kubernetes 의 핵심 그룹화 메커니즘 중 하나입니다. Kubernetes 리소스는 정확한 Pod 이름을 하드코딩하는 대신 일반적으로 레이블을 비교해 관련 객체를 찾습니다. 따라서 Pod 가 다시 생성되어도 시스템을 유연하게 유지할 수 있습니다.

Setup 단계에서 웹 애플리케이션이 자동으로 시작되었습니다. 이제 애플리케이션의 "주소 라벨"을 찾아보겠습니다.

실행 중인 Pod 의 레이블을 확인하려면 다음 명령을 실행합니다.

kubectl get pods --show-labels

다음과 비슷한 출력이 표시됩니다. web-app-xxxxx ... app=web-app

레이블은 app=web-app입니다. 그러나 현재 Service 는 app: unknown을 찾고 있습니다. 이 값을 수정합니다.

service.yaml 파일을 편집합니다.

nano service.yaml

selector 섹션을 Pod 의 레이블과 일치하도록 변경합니다.

selector:
  app: web-app

저장하고 종료합니다. 이제 Service 가 트래픽을 정확히 어디로 전달해야 하는지 알게 됩니다.

적용 및 확인

이제 주소가 올바르게 설정되었으므로 Service 를 활성화합니다.

이 매니페스트를 적용하면 Kubernetes 가 Service 객체를 생성하고, Service 로 들어온 요청을 일치하는 Pod 엔드포인트로 전달할 수 있도록 내부 네트워크 규칙을 구성합니다. 중요한 점은 Service 자체가 애플리케이션을 실행하지 않는다는 것입니다. Service 는 애플리케이션 Pod 앞에서 네트워크 추상화 계층 역할을 합니다.

클러스터에 구성을 적용합니다.

kubectl apply -f service.yaml

다음과 같은 메시지가 표시됩니다. service/my-service created

Service 가 실행 중인지 확인하려면 Service 목록에서 확인합니다.

kubectl get svc my-service

다음 항목이 표시됩니다.

  • NAME: my-service
  • TYPE: NodePort
  • PORT(S): 80:30008/TCP

이 결과는 "전화번호"가 활성화되어 포트 30008 에서 요청을 기다리고 있음을 의미합니다.

애플리케이션에 접속

이제 실제로 확인해 보겠습니다. "외부"(현재 사용 중인 터미널) 에서 애플리케이션에 접속할 수 있을까요?

애플리케이션은 Kubernetes Node 의 30008 포트에 노출되어 있습니다.

여기에는 세 개의 포트가 사용되며, 초보자는 이들을 혼동하기 쉽습니다. nodePort는 노드에서 외부에 개방된 포트이고, port는 Service 추상화 계층이 노출하는 포트이며, targetPort는 실제로 애플리케이션을 제공하는 컨테이너 내부의 포트입니다. 각 포트의 역할을 구분하면 이후에 혼동을 방지할 수 있습니다.

먼저 Minikube 노드의 IP 주소를 확인합니다.

minikube ip

IP 주소가 192.168.49.2라고 가정하겠습니다. 애플리케이션의 전체 주소는 http://192.168.49.2:30008입니다.

curl을 사용해 이 주소에 접속하면 애플리케이션이 응답하는지 확인할 수 있습니다.

curl http://$(minikube ip):30008

"Welcome to nginx!" 페이지의 HTML 코드가 표시됩니다.

이 결과로 요청이 전체 경로를 따라 정상적으로 전달되었음을 확인할 수 있습니다.

  1. Node 의 외부 포트 (30008) 를 호출했습니다.
  2. Service가 요청을 받았습니다.
  3. Service 가 Selector(app: web-app) 를 확인했습니다.
  4. Service 가 해당 레이블과 일치하는 Pod 중 하나로 요청을 전달했습니다.
  5. Pod 가 웹 페이지로 응답했습니다.

요약

이 실습에서는 Service를 사용해 사라지는 Pod IP 주소 문제를 해결했습니다.

다음 작업을 성공적으로 수행했습니다.

  1. 애플리케이션에 연결되는 게이트웨이를 열기 위해 NodePort Service(service.yaml) 를 생성했습니다.
  2. Service 가 관리할 Pod 를 지정하도록 Selector를 구성했습니다.
  3. 안정적인 주소를 사용해 외부에서 실행 중인 애플리케이션에 접속했습니다.

Service 는 Kubernetes 애플리케이션을 연결하는 접착제와 같습니다. 이를 통해 시스템의 여러 부분이 안정적으로 서로 통신할 수 있습니다.