8.3.4 [실습] 인그레스를 이용한 경로 기반 라우팅 설정
이론으로 인그레스(Ingress)가 어떻게 HTTP(S) 트래픽을 관리하고, 인그레스 컨트롤러가 어떤 역할을 하며, 인그레스 리소스 규칙을 어떻게 정의하는지 자세히 살펴보았습니다. 이제는 직접 인그레스 리소스를 생성하고, 그 강력한 L7 라우팅 기능을 실제로 경험해 볼 시간입니다! 이번 실습에서는 두 개의 서로 다른 간단한 웹 애플리케이션을 배포하고, 인그레스를 사용하여 URL 경로에 따라 각기 다른 애플리케이션으로 요청을 라우팅하는 경로 기반 라우팅(Path-based Routing)을 설정해 볼 것입니다.
본 실습을 위해서는 이전 실습들과 마찬가지로 쿠버네티스 클러스터와 kubectl CLI가 준비되어 있어야 합니다. 또한, 클러스터 내에 인그레스 컨트롤러가 반드시 설치되고 실행 중이어야 합니다. 만약 K3s나 Rancher Desktop(k3s 엔진 사용 시)과 같이 Traefik이 기본 내장된 환경을 사용하신다면 별도의 설치가 필요 없을 수 있습니다. 그렇지 않은 경우(예: Minikube, kind, 또는 직접 구성한 클러스터)에는 Nginx Ingress Controller나 다른 인그레스 컨트롤러를 먼저 설치해야 합니다. (Minikube의 경우 minikube addons enable ingress 명령으로 Nginx Ingress Controller를 쉽게 활성화할 수 있습니다.)
자, 그럼 쿠버네티스 인그레스의 스마트한 트래픽 분배 능력을 직접 확인하러 떠나볼까요?
8.3.4.1 두 개의 다른 디플로이먼트/서비스 생성 (예: app-a, app-b)
가장 먼저, 인그레스 라우팅 규칙의 대상이 될 두 개의 서로 다른 간단한 웹 애플리케이션을 배포해야 합니다. 각 애플리케이션은 자신만의 고유한 환영 메시지를 보여주도록 하여, 나중에 라우팅이 올바르게 되었는지 쉽게 확인할 수 있도록 할 것입니다. 이번 실습에서는 간단하게 Nginx 이미지를 사용하되, 각 애플리케이션(디플로이먼트)마다 다른 index.html 내용을 가지도록 ConfigMap을 사용하여 구성해 보겠습니다.
1단계: ConfigMap 생성 (각 앱의 index.html 내용 정의)
먼저, 각 애플리케이션이 사용할 index.html 파일의 내용을 담은 ConfigMap 두 개를 생성합니다.
app-a-html-configmap.yaml:
app-b-html-configmap.yaml:
터미널에서 다음 명령어로 ConfigMap들을 생성합니다.
2단계: App A 디플로이먼트 및 서비스 생성
이제 app-a-html ConfigMap을 사용하여 index.html을 제공하는 Nginx 기반의 ‘App A’ 디플로이먼트와, 이 디플로이먼트를 위한 ClusterIP 타입의 서비스를 생성합니다.
app-a-deployment-service.yaml:
터미널에서 다음 명령어로 App A 관련 리소스들을 생성합니다.
3단계: App B 디플로이먼트 및 서비스 생성
마찬가지로 app-b-html ConfigMap을 사용하는 ‘App B’ 디플로이먼트와 서비스를 생성합니다.
app-b-deployment-service.yaml:
터미널에서 다음 명령어로 App B 관련 리소스들을 생성합니다.
이제 kubectl get deployments와 kubectl get services 명령으로 app-a-deployment, app-b-deployment, app-a-service, app-b-service가 모두 정상적으로 생성되었는지 확인합니다. 또한, kubectl get pods -l app=app-a 와 kubectl get pods -l app=app-b 명령으로 각 앱의 파드가 Running 상태인지 확인합니다.
이로써 우리는 인그레스 라우팅의 대상이 될 두 개의 서로 다른 내부 서비스를 준비했습니다.
8.3.4.2 페이지 라우팅하는 인그레스 생성
이제 드디어 인그레스 리소스를 생성하여, 특정 URL 경로로 들어오는 요청을 앞서 만든 각기 다른 서비스로 전달하도록 설정할 차례입니다. 이번 실습에서는 호스트 이름을 특정하지 않고, 모든 호스트로 들어오는 요청에 대해 /a 경로는 app-a-service로, /b 경로는 app-b-service로 라우팅하는 간단한 경로 기반 라우팅 규칙을 만들 것입니다.
아래 내용을 my-path-ingress.yaml 파일로 저장해 주세요.
이 YAML 파일의 주요 부분을 살펴보겠습니다.
- apiVersion: networking.k8s.io/v1과 kind: Ingress: 이 명세가 인그레스 리소스를 정의함을 나타냅니다.
- metadata.name: path-based-routing-ingress: 인그레스 리소스의 이름을 지정합니다.
- metadata.annotations: 이 부분은 사용하는 인그레스 컨트롤러에 따라 매우 중요할 수 있습니다. 예를 들어, 예전 버전의 Nginx Ingress Controller를 사용할 경우, 경로 재작성(rewrite)을 위해 nginx.ingress.kubernetes.io/rewrite-target: /$2 와 같은 어노테이션이 필요할 수 있습니다 (최신 버전에서는 pathType: Prefix 사용 시 자동으로 처리되기도 합니다). Traefik과 같은 컨트롤러는 이러한 어노테이션 없이도 경로 기반 라우팅이 잘 동작하는 경우가 많습니다. 실습하는 환경의 인그레스 컨트롤러 문서를 반드시 확인하여 필요한 어노테이션이 있는지 확인하고 추가해야 합니다.
- spec.ingressClassName: 만약 클러스터에 여러 종류의 인그레스 컨트롤러가 설치되어 있거나, 기본값 외의 특정 컨트롤러를 사용하고 싶다면 이 필드에 해당 인그레스 컨트롤러의 클래스 이름을 명시해야 합니다. (예: nginx, traefik). 이 필드를 생략하면 기본으로 설정된 인그레스 컨트롤러가 이 인그레스 리소스를 처리하게 됩니다.
- spec.rules: 라우팅 규칙을 정의합니다.
- host 필드가 없으므로, 이 규칙은 어떤 호스트 이름으로 요청이 들어오든 적용됩니다.
- paths 배열에는 두 개의 경로 규칙이 정의되어 있습니다.
- 첫 번째 규칙: path: /a, pathType: Prefix로 설정되어, /a로 시작하는 모든 경로(예: /a, /a/, /a/anything)의 요청을 app-a-service의 80번 포트로 전달합니다.
- 두 번째 규칙: path: /b, pathType: Prefix로 설정되어, /b로 시작하는 모든 경로의 요청을 app-b-service의 80번 포트로 전달합니다.
이제 터미널에서 다음 명령어로 인그레스 리소스를 생성합니다.
“ingress.networking.k8s.io/path-based-routing-ingress created” 메시지가 출력됩니다. 생성된 인그레스의 상태를 확인합니다.
출력 결과를 보면 CLASS, HOSTS, ADDRESS, PORTS, AGE 등의 정보가 표시됩니다. HOSTS는 * (모든 호스트)로, ADDRESS에는 인그레스 컨트롤러가 외부로 노출되는 IP 주소 또는 호스트 이름이 표시될 것입니다. (이 주소가 실제로 외부에서 접근 가능한 주소입니다. Minikube에서는 minikube ip로 얻은 주소이거나, minikube tunnel 실행 후 할당되는 주소일 수 있습니다. Docker Desktop은 localhost일 수 있습니다.) 이 ADDRESS를 잘 기억해 두세요.
8.3.4.3 외부에서 접속하여 라우팅 확인
이제 모든 준비가 끝났습니다! 외부에서 인그레스 컨트롤러의 주소로 접속하여, 우리가 정의한 경로 기반 라우팅 규칙이 올바르게 동작하는지 확인해 볼 차례입니다.
앞서 kubectl get ingress 명령으로 확인한 인그레스 컨트롤러의 ADDRESS (예: 192.168.49.2 또는 localhost)를 사용합니다.
1. /a 경로로 접속하여 App A 응답 확인:
웹 브라우저 주소창에 http://<인그레스_ADDRESS>/a (예: http://192.168.49.2/a 또는 http://localhost/a)를 입력하거나, 터미널에서 curl 명령을 실행합니다.
“Hello from Application A!” 라는 메시지가 포함된 HTML 응답을 받아야 합니다. 이는 /a 경로로 들어온 요청이 성공적으로 app-a-service로 라우팅되었음을 의미합니다. /a/test 와 같이 하위 경로로 접속해도 동일하게 App A로 라우팅되어야 합니다 (pathType: Prefix 때문).
2. /b 경로로 접속하여 App B 응답 확인:
이번에는 웹 브라우저 주소창에 http://<인그레스_ADDRESS>/b (예: http://192.168.49.2/b 또는 http://localhost/b)를 입력하거나, 터미널에서 curl 명령을 실행합니다.
“Greetings from Application B!” 라는 메시지가 포함된 HTML 응답을 받아야 합니다. 이는 /b 경로로 들어온 요청이 성공적으로 app-b-service로 라우팅되었음을 의미합니다.
만약 라우팅이 제대로 동작하지 않는다면:
- 인그레스 컨트롤러가 정상적으로 실행 중인지 확인하세요 (kubectl get pods -n <인그레스_컨트롤러_네임스페이스>).
- 인그레스 리소스의 ADDRESS가 올바르게 할당되었는지, 그리고 해당 주소로 실제로 접근 가능한지 확인하세요.
- 인그레스 리소스의 annotations가 사용 중인 인그레스 컨트롤러에 맞게 올바르게 설정되었는지 다시 한번 확인하세요. (특히 Nginx Ingress Controller의 rewrite-target 관련 어노테이션은 자주 문제를 일으키는 부분입니다.)
- 인그레스 컨트롤러의 로그를 확인하여 오류 메시지가 있는지 살펴보세요 (kubectl logs -n <인그레스_컨트롤러_네임스페이스> <인그레스_컨트롤러_파드이름>).
이 실습을 통해 우리는 두 개의 서로 다른 애플리케이션을 배포하고, 인그레스 리소스를 사용하여 URL 경로에 따라 각기 다른 애플리케이션으로 요청을 성공적으로 라우팅하는 것을 직접 확인했습니다. 인그레스는 이처럼 복잡한 L7 라우팅 요구사항을 쿠버네티스 환경에서 매우 유연하고 강력하게 지원하며, 마이크로서비스 아키텍처의 외부 노출을 관리하는 데 핵심적인 역할을 수행합니다. 호스트 기반 라우팅이나 SSL/TLS 종료와 같은 다른 기능들도 유사한 방식으로 설정하고 테스트해 볼 수 있을 것입니다.