[k8s/스프링] 인그레스 설정과 컨텍스트 패스

쿠버네티스 클러스터 내부의 서비스(Service) 오브젝트에 대한 접근을 관리하는 오브젝트인 인그레스(Ingress)는 리소스에 정의된 규칙에 따라 라우팅을 수행한다. 인그레스의 라우팅 종류에는 단일 서비스로의 라우팅, 하나 이상의 서비스로의 라우팅(간단한 팬아웃(fanout)), 이름 기반의 가상 호스팅 등 여러가지가 있다.

하나 이상의 서비스로 라우팅하는 경우 인그레스는 클러스터 외부에서 단일 IP 또는 도메인으로 하나 이상의 서비스로 트래픽을 라우팅한다. 경로(path) 기반으로 하나 이상의 서비스에 대해 라우팅하는 경우 서비스는 각각의 경로에 대해 포트 매핑을 수행하여 수신 포트에 대해 타겟 포트에 해당하는 파드로 트래픽을 라우팅한다.

애플리케이션 서비스인 파드는 인그레스와 서비스 오브젝트에 의해 정해진 규칙에 의해 클러스터 외부로부터의 요청을 받을 수 있게 된다. 이 경우 애플리케이션은 최종적으로 유입된(패스가 포함된) URL에 대해 핸들러 메서드를 통한 요청 처리를 수행한다. 컨텍스트 패스(context path)가 설정되어 있는 경우 애플리케이션은 컨텍스트 패스 이후의 경로를 컨트롤러에서 처리한다. 따라서 의도된 컨텍스트 패스 설정 적용을 위해서는 인그레스에 설정한 경로의 패스 그대로 컨텍스트 패스를 설정해야 한다.


스웨거 UI 커스텀 패스 설정

springdoc-openapi를 사용하는 경우 스웨거(swagger) UI 페이지의 기본 경로는 hostname:port/context-path/swagger-ui.html이며 애플리케이션 프로퍼티 설정을 통해 스웨거 페이지 진입 경로를 변경할 수 있다. 페이지 진입 시 커스텀 패스는 컨텍스트 패스 뒤에 입력해야 한다.

인그레스에 설정한 경로, 컨텍스트 패스, 커스텀 패스의 설정에 따라 다음과 같은 처리가 이루어진다.

  • 인그레스에 설정한 경로가 hostname/path이고, 컨텍스트 패스가 ` 일 경우 스웨거 UI의 커스텀 패스가 /이면 hostname/path` 경로로 요청 시 404가 응답된다.
  • 인그레스에 설정한 경로가 hostname/path이고, 컨텍스트 패스가 ` 일 경우, 스웨거 UI의 커스텀 패스가 /path이면 hostname/path 경로로 요청 시 라이브러리에 의해 리디렉션 처리가 정상적으로 일어나지만 hostname/swagger-ui/index.html`로 리디렉션 되고 404가 응답된다.
  • 인그레스에 설정한 경로가 hostname/path이고, 컨텍스트 패스가 context-path, 스웨거 UI의 커스텀 패스가 /custom-path이면 hostname/path/context-path/custom-path 경로로 요청 시 404가 응답된다.


따라서 의도된 컨텍스트 패스 및 커스텀 패스 설정 적용을 위해서는 인그레스에 설정한 경로의 패스 그대로 컨텍스트 패스를 설정해야 한다. hostname/path인 경우 컨텍스트 패스를 /path로 설정해야 한다. 스웨거 UI의 기본 경로에 접근하려면 hostname/path/swagger-ui.html를 사용하고 커스텀 패스를 적용한 경우 hostname/path/custom-path를 사용하여 접근한다.


스프링의 컨텍스트 패스 설정

스프링 부트 애플리케이션은 기본적으로 루트 컨텍스트 패스(/) 상에서 리소스 웹 요청을 처리한다. 관련 빈 구성, 커맨드 라인 인자, 자바 시스템 프로퍼티, OS 환경 변수, 애플리케이션 프로퍼티 설정 방법 중 하나를 통해 웹 애플리케이션의 컨텍스트 패스를 지정할 수 있으며 가장 간단한 방법은 애플리케이션 프로퍼티를 사용하는 것이다.

웹 컨테이너로 서블릿 컨테이너를 사용하는 스프링 MVC의 경우 관련 애플리케이션 프로퍼티는 server.servlet.context-path이다. 리액터 네티를 사용하는 스프링 웹플럭스의 경우 스프링 2.3 버전 부터 설정이 가능하며 관련 프로퍼티는 spring.webflux.base-path이다. 웹플럭스는 서블릿 컨테이너를 사용하여 구성할 수도 있으며 이 경우 server.servlet.context-path를 사용해야 한다.


트레일링 슬래시

트레일링 슬래시(trailing slash)란 URL 끝에 붙는 슬래시를 말한다. 트레일링 슬래시가 없는 URL과 슬래시가 있는 URL은 서로 다른 URL이다. URL에서 슬래시는 리소스의 계층을 구분하기 위한 용도이므로 슬래시를 추가한다는 것은 계층을 하나 더 구분한다는 의미이다.

하위 리소스가 없는 리소스의 경우 트레일링 슬래시가 없어야 하며, 리소스가 컬렉션 리소스인 경우 트레일링 슬래시가 있어야 한다. 파일 시스템에서 트레일링 슬래시가 없는 URL은 일반적으로 파일을, 슬래시가 있는 URL은 일반적으로 디렉토리를 의미하며 두 URL은 명확히 다른 것을 알 수 있지만 웹에서는 파일과 디렉토리 사이의 명확한 구분이 존재하지 않아 트레일링 슬래시의 목적과 중요성에 대한 혼란이 발생하고 있다. 대다수의 클라이언트 사용자는 트레일링 슬래시 구분 없이 URL을 입력하므로 서버는 두 URL에 대한 요청 처리를 수행해야 할 수 있으며 따라서 트레일링 슬래시가 없는 URL 요청에 대해 슬래시가 있는 URL로 영구 리디렉션 처리(301 Moved Permanently)를 수행하는 것이 권장되기도 한다.

스프링 6 버전에서 트레일링 슬래시에 대한 리디렉션 처리를 기본적으로 비활성화하고 두 URL을 구분하는 내용의 이슈링크가 생성되었고 해당 내용이 반영되어 스프링 부트 3 버전도 영향을 받게 되었다. 따라서 트레일링 슬래시가 없는 URL과 슬래시가 있는 URL이 동일하게 처리되지 않는다. 따라서 컨트롤러가 트레일링 슬래시가 있는 URL을 처리하도록 별도의 핸들러 메서드를 정의하지 않는다면 슬래시가 있는 URL 요청에 대해 404로 응답을 처리한다. 이전 버전에서는 해당 처리가 기본적으로 활성화되어 있었다. 이러한 기본 기능 동작 변경으로 인해 기존 API의 호환성 유지에 대한 고려가 충분히 이루어진 후 프레임워크 마이그레이션을 진행하는 것이 좋다.

웹 서버인 엔진엑스(Nginx)의 경우 트레일링 슬래시가 있는 URL에 대해 라우팅 처리를 한 경우 트레일링 슬래시가 없는 URL로 요청을 하면 기본적으로 슬래시가 있는 URL로 301 영구 리디렉션 처리를 수행한다.

location /path/ {
  proxy_pass http://hostname/
}


두 URL을 구분하고 리디렉션 처리를 비활성화하려면 다음과 같이 트레일링 슬래시가 없는 URL에 대해 라우팅 처리를 한다.

location /path {
  proxy_pass http://hostname/
}


참고

Comments