티스토리 뷰

작성일: 2025년 12월 18일
카테고리: Kubernetes, Networking, Architecture
키워드: Gateway API, Ingress, Cross-Namespace Reference, ReferenceGrant, Kubernetes

요약

Kubernetes Gateway API는 Ingress의 한계를 해결하기 위해 처음부터 다시 설계된 API다. Role-Oriented Design을 통해 Infrastructure Provider, Cluster Operator, Application Developer 역할을 명확히 분리하고, Cross-Namespace Reference와 ReferenceGrant를 통해 멀티테넌시 환경에서 안전한 리소스 공유를 지원한다. 이 글에서는 Ingress의 문제점, Gateway API의 설계 원칙, 그리고 실제 적용 방법을 다룬다.

들어가며

Kubernetes에서 API를 외부에 노출하는 것은 생각보다 복잡하다. 단순히 Service를 LoadBalancer 타입으로 변경하는 것을 넘어, L7 라우팅, TLS 종료, 인증 등 다양한 요구사항을 처리해야 한다.

Kubernetes에서 외부 트래픽을 처리하는 방법은 크게 발전해왔다:

년도 기술 특징
2015 Service (NodePort, LoadBalancer) 기본적인 L4 로드밸런싱
2016 Ingress (v1beta1) L7 라우팅 표준화 시도
2020 Ingress GA (v1) 안정화, 하지만 한계 명확
2021 Gateway API (v1alpha1) 완전히 새로운 설계
2023 Gateway API GA (v1) 프로덕션 준비 완료

Gateway API는 Ingress의 "개선판"이 아니라, 처음부터 다시 설계된 완전히 새로운 API다.

Ingress의 한계

문제 1: 단일 네임스페이스 제약

# Ingress - 같은 네임스페이스의 Service만 참조 가능
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: team-a  # 이 네임스페이스에 있는 Service만
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: my-service  # team-a 네임스페이스의 서비스만 가능
                port:
                  number: 80

결과: 중앙 집중식 Gateway 관리가 어려움

문제 2: Annotation 지옥

# 실제 프로덕션 Ingress 예시 (NGINX)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # NGINX 전용
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    # ... 더 많은 annotation들

문제점:

문제 설명
구현체마다 다른 annotation NGINX, Traefik, Kong 모두 다름
타입 안정성 없음 모든 값이 문자열
문서 찾기 어려움 각 구현체 문서를 따로 확인
이식성 제로 구현체 변경 시 annotation 전체 수정

문제 3: 역할 분리 불가

flowchart TB
    subgraph Problem["Ingress의 권한 문제"]
        I[Ingress 리소스]

        I --> Q1["누가 TLS 인증서를 관리?"]
        I --> Q2["누가 포트를 열 수 있나?"]
        I --> Q3["누가 라우팅 규칙을 정의?"]

        Q1 & Q2 & Q3 --> A["모두 같은 리소스에서<br/>같은 권한으로 관리"]
    end

    style Problem stroke:#dc2626,stroke-width:2px

인프라 팀 vs 개발 팀의 책임 분리가 불가능

문제 요약

문제 영향
단일 네임스페이스 중앙 Gateway 관리 불가
Annotation 기반 이식성 없음, 타입 안정성 없음
역할 분리 불가 보안 및 운영 복잡성 증가
제한된 기능 고급 라우팅, 트래픽 분할 어려움

Gateway API의 탄생

SIG-Network의 새로운 접근

Kubernetes SIG-Network는 Ingress를 패치하는 대신 완전히 새로운 API를 설계하기로 결정했다.

설계 원칙 (공식):

원칙 설명
Role-oriented 역할별 리소스 분리
Portable 구현체 간 이식성 보장
Expressive 복잡한 라우팅 표현 가능
Extensible 확장 가능한 구조

리소스 분리

flowchart LR
    subgraph Ingress["Ingress (단일 리소스)"]
        I["Ingress<br/>- TLS 설정<br/>- 호스트/포트<br/>- 라우팅 규칙<br/>- 백엔드 참조<br/>모두 한 곳에!"]
    end

    subgraph GatewayAPI["Gateway API (분리된 리소스)"]
        GC["GatewayClass<br/>구현체 정의"]
        GW["Gateway<br/>포트/호스트/TLS"]
        HR["HTTPRoute<br/>라우팅 규칙"]
        BE["Backend/Service<br/>백엔드 정의"]

        GC --> GW --> HR --> BE
    end

    Ingress -->|진화| GatewayAPI

    style Ingress stroke:#dc2626,stroke-width:2px
    style GatewayAPI stroke:#16a34a,stroke-width:2px

Role-Oriented Design

Gateway API의 핵심 혁신은 역할 기반 리소스 분리다.

세 가지 역할

flowchart TB
    subgraph Role1["Infrastructure Provider"]
        GC[GatewayClass]
        GC_DESC["Gateway 구현체 제공<br/>Envoy, Kong, Istio, Traefik 등<br/>클러스터 스코프 (전역)"]
    end

    subgraph Role2["Cluster Operator"]
        GW[Gateway]
        RG[ReferenceGrant]
        GW_DESC["어떤 포트/호스트를 열지 결정<br/>TLS 인증서 관리<br/>네임스페이스: gateway-system"]
    end

    subgraph Role3["Application Developer"]
        HR[HTTPRoute / GRPCRoute]
        BE[Backend / Service]
        HR_DESC["앱별 라우팅 규칙 정의<br/>자신의 네임스페이스에서 관리"]
    end

    GC --> GW
    GW --> HR
    HR --> BE

    style Role1 stroke:#2563eb,stroke-width:2px
    style Role2 stroke:#7c3aed,stroke-width:2px
    style Role3 stroke:#16a34a,stroke-width:2px

역할별 책임

역할 리소스 책임 RBAC 범위
Infrastructure Provider GatewayClass Gateway 구현체 배포 클러스터 관리자
Cluster Operator Gateway, ReferenceGrant 진입점 설정, 보안 정책 인프라 네임스페이스
Application Developer HTTPRoute, Backend 앱 라우팅 규칙 앱 네임스페이스

실제 예시: 권한 분리

# 인프라 팀만 Gateway 생성 가능
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gateway-admin
  namespace: gateway-system
rules:
  - apiGroups: ["gateway.networking.k8s.io"]
    resources: ["gateways"]
    verbs: ["*"]
---
# 개발 팀은 HTTPRoute만 생성 가능
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: route-admin
  namespace: team-a
rules:
  - apiGroups: ["gateway.networking.k8s.io"]
    resources: ["httproutes"]
    verbs: ["*"]
  # gateways 권한 없음!

Cross-Namespace Reference

핵심 혁신

Gateway API는 다른 네임스페이스의 리소스를 참조할 수 있다:

# team-a 네임스페이스의 HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route
  namespace: team-a  # 개발팀 네임스페이스
spec:
  parentRefs:
    - name: shared-gateway
      namespace: gateway-system  # 인프라 네임스페이스 참조
  hostnames:
    - app-a.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: my-service
          port: 8080

이것이 가능하게 하는 아키텍처

flowchart TB
    subgraph Cluster["Kubernetes Cluster"]
        subgraph NS_Infra["gateway-system (인프라)"]
            GW["Gateway<br/>shared-gateway<br/>*.example.com:443"]
            RG["ReferenceGrant<br/>(Cross-NS 허용)"]
        end

        subgraph NS_A["team-a (팀 A)"]
            HR_A["HTTPRoute<br/>app-a.example.com"]
            SVC_A["Service<br/>my-service"]
        end

        subgraph NS_B["team-b (팀 B)"]
            HR_B["HTTPRoute<br/>app-b.example.com"]
            SVC_B["Service<br/>other-service"]
        end

        subgraph NS_C["team-c (팀 C)"]
            HR_C["HTTPRoute<br/>app-c.example.com"]
            SVC_C["Service<br/>another-service"]
        end
    end

    HR_A & HR_B & HR_C -.parentRef.-> GW
    RG -.허용.-> HR_A & HR_B & HR_C

    style NS_Infra stroke:#6366f1,stroke-width:2px
    style NS_A stroke:#16a34a,stroke-width:2px
    style NS_B stroke:#f59e0b,stroke-width:2px
    style NS_C stroke:#dc2626,stroke-width:2px

공식 문서의 설명

"Gateway API is designed with multi-tenancy in mind."

Routes can attach to Gateways across namespace boundaries. This allows the infrastructure team to manage Gateways centrally while application teams define their routing rules in their own namespaces.

Gateway API Official Documentation

ReferenceGrant: 보안 메커니즘

Cross-Namespace Reference는 강력하지만, 보안이 필요하다. ReferenceGrant가 이를 제어한다.

ReferenceGrant 개념

sequenceDiagram
    participant HR as HTTPRoute<br/>(team-a)
    participant RG as ReferenceGrant<br/>(gateway-system)
    participant GW as Gateway<br/>(gateway-system)
    participant Controller as Gateway Controller

    HR->>Controller: parentRef: gateway-system/shared-gateway
    Controller->>RG: ReferenceGrant 확인

    alt ReferenceGrant 존재
        RG-->>Controller: 허용됨
        Controller->>GW: Route 연결
        Controller-->>HR: Status: Accepted
    else ReferenceGrant 없음
        RG-->>Controller: 거부됨
        Controller-->>HR: Status: RefNotPermitted
    end

ReferenceGrant 예시

# gateway-system 네임스페이스에서 정의
# "다른 네임스페이스의 HTTPRoute가 내 Gateway를 참조해도 됨"
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-routes-from-all
  namespace: gateway-system
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: team-a      # 특정 네임스페이스만 허용
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: team-b
  to:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: shared-gateway   # 특정 Gateway만 허용 (선택)

보안 원칙

원칙 설명
명시적 허용 기본은 거부, ReferenceGrant로 허용
대상 네임스페이스에서 정의 참조 "받는" 쪽에서 허용 결정
세분화된 제어 네임스페이스, 리소스 종류, 이름까지 제한 가능

Gateway API 실전 적용

기본 구조

# 1. GatewayClass (Envoy Gateway 설치 시 자동)
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
# 2. Gateway (인프라 레이어)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
  namespace: gateway-system
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      hostname: "*.api.example.com"
      port: 443
      protocol: HTTPS
      tls:
        certificateRefs:
          - name: wildcard-api-tls
---
# 3. ReferenceGrant (Cross-NS 허용)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-tenant-routes
  namespace: gateway-system
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: "*"  # 모든 테넌트 네임스페이스 허용
  to:
    - group: gateway.networking.k8s.io
      kind: Gateway
---
# 4. HTTPRoute (테넌트 레이어)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-api-route
  namespace: team-a
spec:
  parentRefs:
    - name: shared-gateway
      namespace: gateway-system  # Cross-NS Reference
  hostnames:
    - app-a.api.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: my-backend
          port: 8080

표준 준수 체크리스트

Gateway API 원칙 구현 방법 상태
Role-Oriented 인프라/테넌트 네임스페이스 분리 필수
Cross-Namespace HTTPRoute → Gateway 참조 필수
ReferenceGrant 테넌트 Route 허용 정책 필수
Portable 표준 CRD 사용 권장
Expressive 고급 라우팅, 필터, 정책 선택

결론

Gateway API vs Ingress

flowchart LR
    subgraph Ingress["Ingress"]
        I1["단일 리소스"]
        I2["단일 네임스페이스"]
        I3["Annotation 기반"]
        I4["역할 분리 불가"]
    end

    subgraph GatewayAPI["Gateway API"]
        G1["역할별 리소스 분리"]
        G2["Cross-Namespace 지원"]
        G3["타입 안정성 있는 스펙"]
        G4["RBAC 친화적"]
    end

    Ingress -->|"재설계"| GatewayAPI

    style Ingress stroke:#dc2626,stroke-width:2px
    style GatewayAPI stroke:#16a34a,stroke-width:2px

핵심 포인트

Gateway API의 Cross-Namespace 설계는 "꼼수"가 아니라 표준이다:

  1. 의도적 설계: SIG-Network가 멀티테넌시를 위해 설계
  2. Role-Oriented: 인프라 팀과 개발 팀 책임 분리
  3. 보안 내장: ReferenceGrant로 명시적 허용 필요
  4. 업계 표준: Envoy, Kong, Istio, Traefik 모두 지원

요약 다이어그램

flowchart TB
    subgraph Cluster["Kubernetes Cluster"]
        subgraph GC["GatewayClass (클러스터 스코프)"]
            GC_DESC["구현체 정의: envoy-gateway, kong, istio..."]
        end

        subgraph Infra["gateway-system namespace (인프라 팀)"]
            GW["Gateway<br/>포트, 호스트, TLS"]
            RG["ReferenceGrant<br/>Cross-NS 허용 정책"]
        end

        subgraph TeamA["team-a NS (개발팀 A)"]
            HR_A["HTTPRoute"]
            SVC_A["Service"]
        end

        subgraph TeamB["team-b NS (개발팀 B)"]
            HR_B["HTTPRoute"]
            SVC_B["Service"]
        end

        subgraph TeamC["team-c NS (개발팀 C)"]
            HR_C["HTTPRoute"]
            SVC_C["Service"]
        end
    end

    GC --> Infra
    HR_A & HR_B & HR_C -.->|Cross-Namespace<br/>Reference| GW

    style GC stroke:#2563eb,stroke-width:2px
    style Infra stroke:#7c3aed,stroke-width:2px
    style TeamA stroke:#16a34a,stroke-width:2px
    style TeamB stroke:#f59e0b,stroke-width:2px
    style TeamC stroke:#dc2626,stroke-width:2px

참고 자료

공식 문서

구현체

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함