목록으로

Programming Notes

# Ingress2Gateway 1.0 발표: Gateway API로 가는 길

2026년 3월로 예정된 Ingress-NGINX 지원 종료 와 함께, 쿠버네티스 네트워킹 환경은 전환점에 서 있습니다. 대부분의 조직에게 Gateway API 로 마이그레이션할지 여부가 아니라, 어떻게 안전하게 마이그레이션할지가 문제입니다. Ingress에서 Gateway...

2026년 3월로 예정된 Ingress-NGINX 지원 종료와 함께, 쿠버네티스 네트워킹 환경은 전환점에 서 있습니다. 대부분의 조직에게 Gateway API로 마이그레이션할지 여부가 아니라, 어떻게 안전하게 마이그레이션할지가 문제입니다.

Ingress에서 Gateway API로 마이그레이션하는 것은 API 설계의 근본적인 변화입니다. Gateway API는 쿠버네티스 네이티브 RBAC를 강력하게 지원하는 모듈식의 확장 가능한 API를 제공합니다. 반대로, Ingress API는 단순하며, Ingress-NGINX와 같은 구현체는 특이한 어노테이션, ConfigMap 및 CRD를 통해 API를 확장합니다. Ingress-NGINX와 같은 Ingress 컨트롤러에서 마이그레이션하는 것은 Ingress 컨트롤러의 모든 뉘앙스를 파악하고, 그 동작을 Gateway API에 매핑하는 어려운 과제를 안겨줍니다.

Ingress2Gateway는 팀이 Ingress에서 Gateway API로 자신 있게 전환할 수 있도록 돕는 보조 도구입니다. 이 도구는 구현체별 어노테이션과 함께 Ingress 리소스/매니페스트를 Gateway API로 변환하며, 변환할 수 없는 설정에 대해 경고하고 제안을 제공합니다.

오늘, SIG Network는 Ingress2Gateway 1.0 릴리스를 발표하게 된 것을 자랑스럽게 생각합니다. 이 중요한 이정표는 네트워킹 스택을 현대화할 준비가 된 팀을 위한 안정적이고 테스트를 거친 마이그레이션 도우미를 의미합니다.

Ingress2Gateway 1.0

Ingress-NGINX 어노테이션 지원

1.0 릴리스의 주요 개선 사항은 Ingress-NGINX에 대한 더욱 포괄적인 지원입니다. 1.0 릴리스 이전에는 Ingress2Gateway가 세 가지 Ingress-NGINX 어노테이션만 지원했습니다. 1.0 릴리스에서는 Ingress2Gateway가 30개 이상의 일반적인 어노테이션(CORS, 백엔드 TLS, 정규식 매칭, 경로 재작성 등)을 지원합니다.

포괄적인 통합 테스트

지원되는 각 Ingress-NGINX 어노테이션과 일반적인 어노테이션의 대표적인 조합은 Ingress-NGINX 설정과 생성된 Gateway API의 동작 동등성을 검증하는 컨트롤러 수준의 통합 테스트를 통해 지원됩니다. 이 테스트는 실제 클러스터에서 실제 컨트롤러를 실행하고, YAML 구조뿐만 아니라 런타임 동작(라우팅, 리다이렉트, 재작성 등)을 비교합니다.

테스트는 다음을 수행합니다:

  • Ingress-NGINX 컨트롤러를 실행합니다.
  • 여러 Gateway API 컨트롤러를 실행합니다.
  • 구현체별 구성이 포함된 Ingress 리소스를 적용합니다.
  • ingress2gateway로 Ingress 리소스를 Gateway API로 변환하고 생성된 매니페스트를 적용합니다.
  • Gateway API 컨트롤러와 Ingress 컨트롤러가 동등한 동작을 보이는지 확인합니다.

포괄적인 테스트 스위트는 개발 중 버그를 잡을 뿐만 아니라, 특히 예상치 못한 엣지 케이스와 기본값을 고려할 때, 프로덕션에서 문제를 발견하는 일이 없도록 변환의 정확성을 보장합니다.

알림 및 오류 처리

마이그레이션은 "원클릭"으로 이루어지는 작업이 아닙니다. 미묘한 차이와 변환 불가능한 동작을 표면화하는 것은 지원되는 설정을 변환하는 것만큼 중요합니다. 1.0 릴리스는 알림의 형식과 내용을 개선하여 무엇이 누락되었고 어떻게 수정할 수 있는지 명확하게 보여줍니다.

Ingress2Gateway 사용법

Ingress2Gateway는 마이그레이션 보조 도구이지, 단 한 번의 교체가 아닙니다. 목표는 다음과 같습니다:

  • 지원되는 Ingress 구성 및 동작을 마이그레이션합니다.
  • 지원되지 않는 구성을 식별하고 대안을 제안합니다.
  • 바람직하지 않은 구성을 재평가하고 잠재적으로 폐기합니다.

이 섹션의 나머지 부분에서는 다음 Ingress-NGINX 구성을 안전하게 마이그레이션하는 방법을 보여줍니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "1G"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "1"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "1"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "Request-Id: $req_id";
  name: my-ingress
  namespace: my-ns
spec:
  ingressClassName: nginx
  rules:
  - host: my-host.example.com
    http:
      paths:
      - backend:
          service:
            name: website-service
            port:
              number: 80
        path: /users/(\d+)
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - my-host.example.com
    secretName: my-secret

1. Ingress2Gateway 설치

Go 환경이 설정되어 있다면, 다음 명령어로 Ingress2Gateway를 설치할 수 있습니다:

go install github.com/kubernetes-sigs/[email protected]

그렇지 않다면, 다음 명령어를 사용하세요:

brew install ingress2gateway

GitHub에서 바이너리를 다운로드하거나 소스 코드에서 빌드할 수도 있습니다.

2. Ingress2Gateway 실행

Ingress2Gateway에 Ingress 매니페스트를 직접 전달하거나, 도구가 클러스터에서 직접 읽도록 할 수 있습니다.

# 파일 전달
ingress2gateway print --input-file my-manifest.yaml,my-other-manifest.yaml --providers=ingress-nginx > gwapi.yaml
# 클러스터의 네임스페이스 사용
ingress2gateway print --namespace my-api --providers=ingress-nginx > gwapi.yaml
# 또는 클러스터 전체 사용
ingress2gateway print --providers=ingress-nginx --all-namespaces > gwapi.yaml

참고:

또한 --emitter <agentgateway|envoy-gateway|kgateway>를 전달하여 구현체별 확장 기능을 출력할 수도 있습니다.

3. 출력 검토

이것이 가장 중요한 단계입니다. 이전 섹션의 명령은 Gateway API 매니페스트를 gwapi.yaml로 출력하며, 정확하게 변환되지 않은 내용과 수동으로 검토해야 할 사항을 설명하는 경고도 발생시킵니다.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  annotations:
    gateway.networking.k8s.io/generator: ingress2gateway-dev
  name: nginx
  namespace: my-ns
spec:
  gatewayClassName: nginx
  listeners:
  - hostname: my-host.example.com
    name: my-host-example-com-http
    port: 80
    protocol: HTTP
  - hostname: my-host.example.com
    name: my-host-example-com-https
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - group: ""
        kind: Secret
        name: my-secret
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  annotations:
    gateway.networking.k8s.io/generator: ingress2gateway-dev
  name: my-ingress-my-host-example-com
  namespace: my-ns
spec:
  hostnames:
  - my-host.example.com
  parentRefs:
  - name: nginx
    port: 443
  rules:
  - backendRefs:
    - name: website-service
      port: 80
    filters:
    - cors:
        allowCredentials: true
        allowHeaders:
        - DNT
        - Keep-Alive
        - User-Agent
        - X-Requested-With
        - If-Modified-Since
        - Cache-Control
        - Content-Type
        - Range
        - Authorization
        allowMethods:
        - GET
        - PUT
        - POST
        - DELETE
        - PATCH
        - OPTIONS
        allowOrigins:
        - '*'
        maxAge: 1728000
      type: CORS
    matches:
    - path:
        type: RegularExpression
        value: (?i)/users/(\d+).*
    name: rule-0
    timeouts:
      request: 10s
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  annotations:
    gateway.networking.k8s.io/generator: ingress2gateway-dev
  name: my-ingress-my-host-example-com-ssl-redirect
  namespace: my-ns
spec:
  hostnames:
  - my-host.example.com
  parentRefs:
  - name: nginx
    port: 80
  rules:
  - filters:
    - requestRedirect:
        scheme: https
        statusCode: 308
      type: RequestRedirect

Ingress2Gateway는 일부 어노테이션을 Gateway API 동등 항목으로 성공적으로 변환했습니다. 예를 들어, nginx.ingress.kubernetes.io/enable-cors 어노테이션은 CORS 필터로 변환되었습니다. 그러나 자세히 살펴보면, nginx.ingress.kubernetes.io/proxy-{read,send}-timeoutnginx.ingress.kubernetes.io/proxy-body-size 어노테이션은 완벽하게 매핑되지 않습니다. 로그에는 이러한 누락에 대한 이유와 변환의 배경이 설명되어 있습니다.

┌─ WARN ────────────────────────────────────────
│ Unsupported annotation nginx.ingress.kubernetes.io/configuration-snippet
│ source: INGRESS-NGINX
│ object: Ingress: my-ns/my-ingress
└─
┌─ INFO ────────────────────────────────────────
│ Using case-insensitive regex path matches. You may want to change this.
│ source: INGRESS-NGINX
│ object: HTTPRoute: my-ns/my-ingress-my-host-example-com
└─
┌─ WARN ────────────────────────────────────────
│ ingress-nginx only supports TCP-level timeouts; i2gw has made a best-effort translation to Gateway API timeouts.request. Please verify that this meets your needs. See documentation: https://gateway-api.sigs.k8s.io/guides/http-timeouts/
│ source: INGRESS-NGINX
│ object: HTTPRoute: my-ns/my-ingress-my-host-example-com
└─
┌─ WARN ────────────────────────────────────────
│ Failed to apply my-ns.my-ingress.metadata.annotations."nginx.ingress.kubernetes.io/proxy-body-size" from my-ns/my-ingress: Most Gateway API implementations have reasonable body size and buffering defaults
│ source: STANDARD_EMITTER
│ object: HTTPRoute: my-ns/my-ingress-my-host-example-com
└─
┌─ WARN ────────────────────────────────────────
│ Gateway API does not support configuring URL normalization (RFC 3986, Section 6). Please check if this matters for your use case and consult implementation-specific details.
│ source: STANDARD_EMITTER
└─

Ingress2Gateway는 nginx.ingress.kubernetes.io/configuration-snippet 어노테이션을 지원하지 않는다는 경고가 있습니다. 동등한 동작을 구현하기 위해 Gateway API 구현체 문서를 확인해야 합니다.

이 도구는 또한 Ingress-NGINX 정규식 매치가 대소문자를 구분하지 않는 접두사 매치임을 알려주었으며, 이 때문에 (?i)/users/(\d+).*와 같은 매치 패턴이 사용되었습니다. 대부분의 조직은 경로 패턴에서 선행 (?i)와 후행 .*를 제거하여 이 동작을 정확하고 대소문자를 구분하는 매치로 변경하기를 원할 것입니다.

Ingress2Gateway는 nginx.ingress.kubernetes.io/proxy-{send,read}-timeout 어노테이션을 HTTP 경로의 10초 요청 타임아웃으로 최선을 다해 변환했습니다. 이 서비스에 대한 요청이 훨씬 짧은, 예를 들어 3초여야 한다면, Gateway API 매니페스트에 해당하는 변경 사항을 적용할 수 있습니다.

또한, nginx.ingress.kubernetes.io/proxy-body-size는 Gateway API 동등 항목이 없으므로 변환되지 않았습니다. 그러나 대부분의 Gateway API 구현체는 최대 본문 크기 및 버퍼링에 대해 합리적인 기본값을 가지고 있으므로, 실제로는 문제가 되지 않을 수 있습니다. 또한, 일부 이미터는 구현체별 확장을 통해 이 어노테이션을 지원할 수도 있습니다. 예를 들어, 이전 ingress2gateway print 명령에 --emitter agentgateway, --emitter envoy-gateway, 또는 --emitter kgateway 플래그를 추가하면, 본문 크기 구성을 캡처하려는 추가적인 구현체별 구성이 생성된 Gateway API 매니페스트에 포함되었을 것입니다.

URL 정규화에 대한 경고도 있습니다. Agentgateway, Envoy Gateway, Kgateway, Istio와 같은 Gateway API 구현체는 어느 정도 URL 정규화를 지원하지만, 동작은 구현체마다 다르며 표준 Gateway API를 통해 구성할 수 없습니다. 사용 사례와 호환되는지 확인하기 위해 Gateway API 구현체의 URL 정규화 동작을 확인하고 테스트해야 합니다.

Ingress-NGINX의 기본 동작과 일치하도록 Ingress2Gateway는 포트 80에 리스너를 추가하고 HTTP 트래픽을 HTTPS로 리다이렉트하는 HTTP 요청 리다이렉트 필터를 추가했습니다. HTTP 트래픽을 전혀 제공하지 않으려면 포트 80의 리스너와 해당 HTTPRoute를 제거할 수 있습니다.

주의:

생성된 출력과 로그를 항상 철저히 검토하세요.

이러한 변경 사항을 수동으로 적용한 후, Gateway API 매니페스트는 다음과 같을 수 있습니다.

---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  annotations:
    gateway.networking.k8s.io/generator: ingress2gateway-dev
  name: nginx
  namespace: my-ns
spec:
  gatewayClassName: nginx
  listeners:
  - hostname: my-host.example.com
    name: my-host-example-com-https
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - group: ""
        kind: Secret
        name: my-secret
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  annotations:
    gateway.networking.k8s.io/generator: ingress2gateway-dev
  name: my-ingress-my-host-example-com
  namespace: my-ns
spec:
  hostnames:
  - my-host.example.com
  parentRefs:
  - name: nginx
    port: 443
  rules:
  - backendRefs:
    - name: website-service
      port: 80
    filters:
    - cors:
        allowCredentials: true
        allowHeaders:
        - DNT
        ...
        allowMethods:
        - GET
        ...
        allowOrigins:
        - '*'
        maxAge: 1728000
      type: CORS
    matches:
    - path:
        type: RegularExpression
        value: /users/(\d+)
    name: rule-0
    timeouts:
      request: 3s

4. 검증

이제 Gateway API 매니페스트가 있으므로, 개발 클러스터에서 철저히 테스트해야 합니다. 이 경우, Gateway API 구현체의 최대 본문 크기 기본값이 적절한지 다시 확인하고, 3초의 타임아웃이 충분한지 검증해야 합니다.

개발 클러스터에서 동작을 검증한 후, 기존 Ingress와 함께 Gateway API 구성을 배포하세요. 가중치 DNS, 클라우드 로드 밸런서 또는 플랫폼의 트래픽 분할 기능을 사용하여 트래픽을 점진적으로 전환하는 것을 강력히 권장합니다. 이렇게 하면 테스트를 통과한 모든 잘못된 구성으로부터 신속하게 복구할 수 있습니다.

마지막으로, 모든 트래픽을 Gateway API 컨트롤러로 전환한 후, Ingress 리소스를 삭제하고 Ingress 컨트롤러를 제거하세요.

결론

Ingress2Gateway 1.0 릴리스는 단지 시작일 뿐이며, Ingress2Gateway를 사용하여 Gateway API로 안전하게 마이그레이션하시길 바랍니다. 2026년 3월 Ingress-NGINX 지원 종료가 다가옴에 따라, 커뮤니티가 구성 커버리지를 늘리고, 테스트를 확장하며, 사용자 경험을 개선하는 데 도움을 주시기를 요청합니다.

Gateway API 관련 리소스

Gateway API의 범위는 광범위하여 부담스러울 수 있습니다. Gateway API 작업에 도움이 될 만한 몇 가지 리소스입니다: