들어가며
쿠버네티스에 서비스를 올리고 나면 곧바로 마주치는 질문이 있습니다. "외부 트래픽을 어떻게 받아서 어디로 보낼 것인가." 가장 표준적인 답은 Ingress 리소스이고, 그 구현체로 가장 널리 쓰여 온 것이 ingress-nginx입니다. 그런데 실제 서비스를 운영하다 보면 단순히 "경로 기반으로 트래픽을 라우팅한다"는 것만으로는 부족해지는 순간이 옵니다.
예를 들어 이런 요구사항들이 쌓이기 시작합니다. 특정 API에는 분당 100회 레이트리밋을 걸어야 하고, 파트너사 호출에는 API 키 인증을 적용해야 하며, 레거시 백엔드로 가는 요청에는 헤더를 변환해 붙여야 하고, 모든 요청을 OpenTelemetry로 추적해 Prometheus 메트릭으로 노출해야 합니다. 이쯤 되면 우리가 필요로 하는 것은 단순한 리버스 프록시가 아니라 API Gateway입니다.
Kong Ingress Controller(이하 KIC)는 바로 이 지점을 노립니다. KIC는 Ingress 컨트롤러의 외형을 하고 있지만, 그 뒤에는 풀스택 API Gateway인 Kong Gateway가 자리합니다. 즉 쿠버네티스 네이티브한 방식(Ingress 리소스, Gateway API, 커스텀 리소스)으로 선언하면, 그 선언이 Kong Gateway의 강력한 플러그인 파이프라인으로 변환되어 동작합니다.
이 글에서는 KIC를 단순 설치 가이드가 아니라 "왜 이렇게 설계되었고, 운영 관점에서 무엇을 알아야 하는가"의 시각으로 깊게 다룹니다. 아키텍처와 동작 모드, 핵심 CRD, 대표 플러그인, Helm 기반 배포, declarative config, 그리고 Gateway API와의 관계와 트러블슈팅까지 코드 중심으로 정리하겠습니다. 기준 버전은 2026년 상반기 시점의 Kong Gateway 3.x 계열, KIC 3.x 계열, Kubernetes v1.32 계열입니다.
2026년의 Ingress 지형 — 왜 지금 Kong을 보는가
먼저 큰 그림을 정리하고 넘어가야 합니다. 2026년 현재 쿠버네티스 인그레스 생태계는 중요한 전환점을 지나고 있습니다.
첫째, Ingress API는 사실상 동결(frozen)되었습니다. 쿠버네티스의 `networking.k8s.io/v1` Ingress는 안정화되었지만, 더 이상 새로운 기능이 추가되지 않습니다. TLS 종료와 host/path 기반 라우팅 정도의 표준 기능만 명세에 들어 있고, 그 외의 모든 고급 기능(헤더 라우팅, 트래픽 분할, 인증, 레이트리밋)은 각 컨트롤러의 어노테이션이라는 비표준 영역으로 밀려나 있습니다.
둘째, 그 후계자로 Gateway API가 표준의 자리를 가져갔습니다. Gateway API는 역할 분리(인프라 운영자 vs 애플리케이션 개발자), 표현력 있는 라우팅, 이식 가능한 명세를 목표로 설계된 차세대 표준이며, 2026년 시점에는 핵심 리소스가 GA에 도달해 프로덕션에서 쓸 수 있는 단계에 들어섰습니다.
셋째, 가장 널리 쓰이던 ingress-nginx는 유지보수 모드 성격으로 전환되는 흐름이 뚜렷합니다. 신규 기능 개발보다 보안 이슈 대응 중심으로 운영되고 있으며, 어노테이션을 통한 임의 설정 주입과 관련된 보안 취약점이 반복적으로 보고되면서, 조직들은 대안을 진지하게 검토하기 시작했습니다.
이 세 가지 흐름이 만나는 지점에서 Kong이 매력적인 선택지로 떠오릅니다. Kong은 Ingress와 Gateway API를 동시에 지원하면서, ingress-nginx의 어노테이션 지옥을 CRD 기반의 구조화된 설정으로 대체하고, 무엇보다 API Gateway급 기능을 플러그인으로 제공하기 때문입니다.
| 항목 | ingress-nginx | Kong Ingress Controller | 순수 Gateway API 구현체 |
| --- | --- | --- | --- |
| 기반 데이터플레인 | NGINX | Kong Gateway(NGINX + Lua/OpenResty) | 구현마다 다름 |
| 표준 인터페이스 | Ingress | Ingress + Gateway API | Gateway API |
| 고급 기능 설정 방식 | 어노테이션/ConfigMap | CRD(KongPlugin 등) + 어노테이션 | 정책 CRD/필터 |
| 인증·레이트리밋 | 제한적 | 플러그인 풍부 | 구현 의존 |
| 옵저버빌리티 | 기본 메트릭 | Prometheus/OTel 플러그인 | 구현 의존 |
| 프로젝트 상태 | 유지보수 중심 | 활발 | 활발 |
표에서 보듯 Kong의 차별점은 "API Gateway 기능을 쿠버네티스 네이티브하게 선언적으로 쓸 수 있다"는 데 있습니다. 그럼 그 구조를 하나씩 뜯어보겠습니다.
Kong Gateway와 KIC — 두 개의 레이어 이해하기
가장 먼저 분명히 해야 할 것은 "Kong Gateway"와 "Kong Ingress Controller"가 별개의 컴포넌트라는 사실입니다. 많은 입문자가 이 둘을 혼동하는데, 둘의 역할을 분리해서 이해하면 이후의 모든 개념이 쉽게 풀립니다.
Kong Gateway는 실제로 트래픽을 처리하는 데이터플레인입니다. NGINX와 OpenResty(LuaJIT) 위에 구축되어 있으며, 들어오는 요청을 라우트(route)와 서비스(service)에 매칭하고, 그 사이에서 플러그인 파이프라인을 실행합니다. 이것이 인증, 레이트리밋, 변환, 로깅을 담당하는 엔진입니다.
Kong Ingress Controller는 컨트롤플레인 역할입니다. 쿠버네티스 API 서버를 감시(watch)하다가, Ingress·Gateway API·Kong CRD 같은 리소스가 생기거나 바뀌면, 그것을 Kong Gateway가 이해하는 설정으로 번역해 주입합니다. 즉 KIC는 "쿠버네티스 선언 → Kong 설정"을 변환하는 번역기이자 동기화 루프입니다.
+-----------------------------------------------------------------------+
| Kubernetes 클러스터 |
| |
| [컨트롤플레인] [데이터플레인] |
| Kong Ingress Controller ───설정 주입──▶ Kong Gateway (프록시) |
| │ ▲ |
| │ watch │ 실제 트래픽 처리 |
| ▼ │ |
| kube-apiserver │ |
| ├─ Ingress / HTTPRoute │ |
| ├─ KongPlugin / KongConsumer │ |
| └─ Service / Endpoints ◀─────────엔드포인트 조회─┘ |
| |
+-----------------------------------------------------------------------+
▲ │
│ kubectl apply ▼
운영자/개발자 외부 클라이언트 요청
이 분리 구조 덕분에 운영자는 두 가지 배포 패턴 중 하나를 고를 수 있습니다. 하나는 컨트롤러와 게이트웨이를 같은 파드 안의 사이드카로 묶어 단순하게 운영하는 방식이고, 다른 하나는 컨트롤플레인과 데이터플레인을 별도 디플로이먼트로 분리해 데이터플레인을 독립적으로 수평 확장하는 방식입니다. 트래픽 규모가 커지면 후자가 일반적입니다.
DB-less 모드 vs DB 모드 — 가장 중요한 선택
KIC를 도입할 때 가장 먼저, 그리고 가장 중요하게 결정해야 하는 것이 데이터플레인의 동작 모드입니다. Kong Gateway는 설정을 보관하는 방식에 따라 두 가지 모드로 동작합니다.
DB-less 모드에서는 Kong이 외부 데이터베이스를 두지 않고, 모든 설정을 메모리에 올린 declarative 설정으로 동작합니다. KIC가 쿠버네티스 리소스를 읽어 declarative 설정(JSON/YAML)을 생성하고, 이를 Kong의 Admin API를 통해 메모리에 통째로 적용합니다. 쿠버네티스 환경에서 권장되는 표준 패턴입니다.
DB 모드에서는 Kong이 PostgreSQL을 백엔드로 두고 설정을 영속화합니다. Admin API로 개별 엔티티를 직접 CRUD할 수 있어 유연하지만, 쿠버네티스 위에서 추가로 상태 저장소를 운영해야 하고 마이그레이션 잡을 관리해야 하는 부담이 생깁니다.
| 비교 항목 | DB-less 모드 | DB 모드(PostgreSQL) |
| --- | --- | --- |
| 설정 저장소 | 메모리(declarative) | PostgreSQL |
| 단일 진실 공급원 | 쿠버네티스 리소스 | 데이터베이스 |
| 운영 복잡도 | 낮음 | 높음(DB 운영·마이그레이션) |
| 수평 확장 | 데이터플레인 무상태로 쉬움 | DB 병목 가능 |
| Admin API 쓰기 | 비활성(읽기 전용 성격) | 활성 |
| GitOps 적합성 | 매우 높음 | 보통 |
| 권장 환경 | 쿠버네티스 일반 | 일부 엔터프라이즈 기능 필요 시 |
핵심 원칙을 한 줄로 요약하면 이렇습니다. 쿠버네티스 위에서 KIC를 쓴다면 특별한 이유가 없는 한 DB-less 모드를 기본값으로 삼는 것이 좋습니다. 쿠버네티스 리소스 자체가 단일 진실 공급원이 되어 GitOps와 자연스럽게 맞물리고, 상태 저장소를 운영하지 않아 장애 표면이 줄어들기 때문입니다.
다음은 DB-less 모드에서 KIC가 만들어 내는 declarative 설정의 형태를 보여 주는 예시입니다. 운영자가 직접 작성하는 일은 드물지만, 트러블슈팅할 때 Kong이 실제로 무엇을 보고 있는지 이해하려면 이 형태를 알아 두는 것이 좋습니다.
_format_version: "3.0"
services:
- name: example-service.default.80
host: example-service.default.svc
port: 80
protocol: http
routes:
- name: example-route
paths:
- /api
strip_path: true
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
consumers:
- username: partner-a
keyauth_credentials:
- key: secret-api-key-value
핵심 CRD — KongPlugin, KongConsumer, KongIngress
KIC의 진짜 힘은 커스텀 리소스에서 나옵니다. 표준 Ingress가 표현하지 못하는 모든 것을, Kong은 CRD로 깔끔하게 표현합니다. 가장 자주 쓰는 세 가지를 살펴보겠습니다.
KongPlugin과 KongClusterPlugin
KongPlugin은 KIC를 쓰는 이유 그 자체라고 해도 과언이 아닙니다. 플러그인 하나를 선언하고, 그것을 Ingress·Service·HTTPRoute·Consumer 같은 대상에 어노테이션으로 붙이면, 해당 트래픽 경로에 플러그인이 적용됩니다.
다음은 레이트리밋 플러그인을 선언하는 예시입니다.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rl-by-minute
namespace: default
config:
minute: 100
policy: local
plugin: rate-limiting
이렇게 선언한 플러그인을 특정 Ingress에 적용하려면, Ingress 쪽에 어노테이션을 답니다. 여러 플러그인을 쉼표로 나열해 동시에 적용할 수도 있습니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: default
annotations:
konghq.com/plugins: rl-by-minute,key-auth-plugin
konghq.com/strip-path: "true"
spec:
ingressClassName: kong
rules:
- host: api.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
KongPlugin은 네임스페이스 범위이고, 같은 역할을 클러스터 전역으로 적용하고 싶을 때는 KongClusterPlugin을 사용합니다. 모든 워크로드에 공통으로 거는 보안 헤더나 전역 로깅 플러그인에 적합합니다.
KongConsumer와 인증
KongConsumer는 Kong 세계에서의 "호출 주체"를 표현합니다. 파트너사, 내부 서비스, 특정 클라이언트 등을 Consumer로 등록하고, 거기에 인증 크리덴셜(API 키, JWT 등)을 연결합니다. 이렇게 하면 "누가 호출했는가"를 식별할 수 있고, Consumer별로 다른 레이트리밋이나 권한을 적용할 수 있습니다.
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: partner-a
namespace: default
annotations:
kubernetes.io/ingress.class: kong
username: partner-a
credentials:
- partner-a-apikey
크리덴셜은 일반적으로 시크릿으로 분리해 관리합니다. 다음은 key-auth용 API 키를 시크릿으로 정의한 예시입니다.
apiVersion: v1
kind: Secret
metadata:
name: partner-a-apikey
namespace: default
labels:
konghq.com/credential: key-auth
type: Opaque
stringData:
key: super-secret-partner-a-key
KongIngress와 신형 CRD의 흐름
KongIngress는 라우트와 서비스의 세부 동작(프로토콜, 타임아웃, 재시도, 경로 처리 방식 등)을 조정하기 위한 전통적인 CRD였습니다. 다만 2026년 시점에는 이 역할이 KongUpstreamPolicy, 그리고 Service 어노테이션과 Gateway API 정책으로 점차 분화되는 흐름입니다. 새로 시작하는 프로젝트라면 KongIngress 하나에 모든 설정을 몰아넣기보다, 업스트림 동작은 KongUpstreamPolicy로, 플러그인은 KongPlugin으로 나누어 표현하는 방식이 권장됩니다.
다음은 업스트림 헬스체크와 로드밸런싱 알고리즘을 KongUpstreamPolicy로 정의한 예시입니다.
apiVersion: configuration.konghq.com/v1beta1
kind: KongUpstreamPolicy
metadata:
name: example-upstream-policy
namespace: default
spec:
algorithm: least-connections
healthchecks:
active:
type: http
httpPath: /healthz
healthy:
interval: 5
successes: 1
unhealthy:
interval: 5
httpFailures: 3
이 정책을 적용하려면 대상 Service에 어노테이션으로 연결합니다.
apiVersion: v1
kind: Service
metadata:
name: example-service
namespace: default
annotations:
konghq.com/upstream-policy: example-upstream-policy
spec:
selector:
app: example
ports:
- port: 80
targetPort: 8080
핵심 플러그인 생태계 둘러보기
Kong의 진짜 가치는 플러그인 생태계입니다. 수십 종의 공식 플러그인과 커뮤니티 플러그인이 있으며, 크게 다섯 갈래로 나눠 이해하면 편합니다.
| 분류 | 대표 플러그인 | 하는 일 |
| --- | --- | --- |
| 인증 | key-auth, jwt, oauth2, basic-auth, ldap-auth, openid-connect | 호출 주체 식별과 인증 |
| 트래픽 제어 | rate-limiting, request-termination, proxy-cache, request-size-limiting | 유량 제어와 보호 |
| 변환 | request-transformer, response-transformer, correlation-id | 헤더·바디·쿼리 조작 |
| 옵저버빌리티 | prometheus, opentelemetry, http-log, file-log, datadog | 메트릭·트레이스·로그 |
| 보안 | cors, ip-restriction, bot-detection, acl | 접근 통제와 방어 |
각 분류를 대표 예시 중심으로 살펴보겠습니다.
인증 — key-auth와 OIDC
가장 단순한 인증은 key-auth입니다. 앞에서 본 것처럼 Consumer에 API 키를 연결하고, 라우트에 key-auth 플러그인을 걸면, 헤더나 쿼리로 전달된 키를 검증해 Consumer를 식별합니다.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: key-auth-plugin
namespace: default
config:
key_names:
- apikey
key_in_header: true
key_in_query: false
plugin: key-auth
엔터프라이즈 환경에서는 openid-connect 플러그인으로 Keycloak이나 사내 IdP와 연동해 OIDC 기반 인증을 적용하는 경우가 많습니다. 이 경우 게이트웨이 단에서 토큰 검증을 처리하므로, 백엔드 서비스는 인증 로직에서 자유로워집니다.
트래픽 제어 — rate-limiting
레이트리밋은 가장 자주 쓰는 플러그인입니다. 분·시·일 단위 한도를 설정할 수 있고, 한도 계산 정책으로 로컬·클러스터·Redis를 고를 수 있습니다. 여러 데이터플레인 파드 사이에서 한도를 공유하려면 Redis 정책이 정확합니다. 로컬 정책은 빠르지만 파드별로 한도가 따로 계산된다는 점을 기억해야 합니다.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rl-redis
namespace: default
config:
minute: 100
hour: 2000
policy: redis
redis:
host: redis-master.default.svc
port: 6379
plugin: rate-limiting
변환 — request-transformer
레거시 백엔드와 통신할 때, 요청 헤더를 추가하거나 제거하거나 바꿔야 하는 경우가 흔합니다. request-transformer는 이런 작업을 게이트웨이 단에서 처리합니다.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: add-legacy-headers
namespace: default
config:
add:
headers:
- "X-Gateway: kong"
- "X-Forwarded-Prefix: /api"
remove:
headers:
- "X-Internal-Token"
plugin: request-transformer
옵저버빌리티 — prometheus와 opentelemetry
운영의 핵심은 가시성입니다. prometheus 플러그인을 전역으로 걸면 요청 수, 지연시간, 상태 코드, 업스트림 헬스 같은 메트릭을 Prometheus 형식으로 노출합니다. opentelemetry 플러그인은 분산 트레이스를 OTLP로 내보내, 게이트웨이를 거치는 요청의 흐름을 추적할 수 있게 합니다.
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
name: prometheus
annotations:
kubernetes.io/ingress.class: kong
labels:
global: "true"
config:
status_code_metrics: true
latency_metrics: true
bandwidth_metrics: true
plugin: prometheus
`global: "true"` 라벨이 붙은 KongClusterPlugin은 모든 라우트에 자동으로 적용됩니다. 옵저버빌리티 플러그인은 이런 전역 적용 방식과 특히 잘 어울립니다.
요청이 흘러가는 전체 경로
지금까지 본 컴포넌트들이 실제 요청에서 어떻게 맞물리는지 한 장의 그림으로 정리하면 다음과 같습니다.
외부 클라이언트
│ GET https://api.example.com/api/orders (apikey 헤더 포함)
▼
[로드밸런서 / Service type=LoadBalancer]
│
▼
[Kong Gateway 데이터플레인 파드]
│
├─ 1. 라우트 매칭: host=api.example.com, path=/api ─▶ example-service
│
├─ 2. 플러그인 파이프라인 (요청 단계)
│ ├─ cors (프리플라이트 처리)
│ ├─ key-auth (apikey 검증 → Consumer=partner-a 식별)
│ ├─ acl (partner-a가 허용 그룹인지 확인)
│ ├─ rate-limiting (partner-a의 분당 한도 확인)
│ └─ request-transformer (헤더 가공)
│
├─ 3. 업스트림 선택 (KongUpstreamPolicy: least-connections + healthcheck)
│
▼
[example-service → 파드 엔드포인트]
│
▼ 응답
[Kong Gateway 데이터플레인]
│
├─ 4. 플러그인 파이프라인 (응답 단계)
│ ├─ response-transformer
│ └─ prometheus / opentelemetry (메트릭·트레이스 기록)
│
▼
외부 클라이언트로 응답 반환
이 흐름에서 중요한 점은 플러그인이 단계와 우선순위에 따라 순서대로 실행된다는 것입니다. 예를 들어 인증(key-auth)은 레이트리밋(rate-limiting)보다 먼저 실행되어야 "누구의 한도인가"를 알 수 있습니다. Kong은 각 플러그인에 기본 우선순위를 두어 이 순서를 보장하며, 필요하면 운영자가 우선순위를 조정할 수도 있습니다.
Ingress와 Gateway API 동시 지원
앞서 짚었듯 2026년의 핵심 화두는 Gateway API입니다. KIC의 큰 장점은 전통적인 Ingress와 신표준 Gateway API를 모두 지원한다는 점입니다. 덕분에 기존 Ingress 자산을 유지하면서 점진적으로 Gateway API로 이전할 수 있습니다.
Gateway API에서는 역할이 분리됩니다. 인프라 운영자는 GatewayClass와 Gateway로 리스너와 인프라를 정의하고, 애플리케이션 개발자는 HTTPRoute로 라우팅 규칙을 선언합니다. KIC는 이 리소스들을 모두 처리합니다.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: kong
spec:
controllerName: konghq.com/kic-gateway-controller
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kong-gateway
namespace: default
spec:
gatewayClassName: kong
listeners:
- name: http
protocol: HTTP
port: 80
HTTPRoute는 host와 path뿐 아니라 헤더, 메서드, 쿼리 파라미터 기반 매칭을 표준으로 표현할 수 있습니다. 이는 Ingress가 끝내 표준화하지 못한 영역이었습니다.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: orders-route
namespace: default
spec:
parentRefs:
- name: kong-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/orders
headers:
- name: X-Api-Version
value: v2
backendRefs:
- name: orders-service
port: 80
플러그인은 Gateway API 환경에서도 동일하게 적용됩니다. HTTPRoute에 KongPlugin 어노테이션을 붙이거나, Gateway API 표준의 정책 부착 메커니즘을 통해 연결합니다. 즉 표준 인터페이스는 Gateway API로 가져가되, Kong의 풍부한 플러그인 생태계는 그대로 누릴 수 있습니다.
실무적인 권장 경로는 이렇습니다. 신규 클러스터라면 처음부터 Gateway API로 시작하고, 기존 Ingress 기반 클러스터라면 KIC로 통일한 뒤 Ingress와 Gateway API를 병행 운영하며 HTTPRoute로 점진 이전하는 것입니다. 두 표준이 같은 컨트롤러 아래에서 공존할 수 있다는 점이 KIC의 큰 강점입니다.
Helm으로 배포하기
이제 실제 배포로 넘어가겠습니다. KIC의 표준 배포 방식은 Helm 차트이며, 단일 차트로 컨트롤러와 게이트웨이를 함께 올릴 수 있습니다. 먼저 Helm 리포지터리를 추가합니다.
helm repo add kong https://charts.konghq.com
helm repo update
kubectl create namespace kong
다음은 DB-less 모드로 배포하기 위한 values 파일 예시입니다. 컨트롤러를 활성화하고, 게이트웨이를 LoadBalancer로 노출하며, 프록시와 Admin API 설정을 명시합니다.
ingressController:
enabled: true
installCRDs: false
ingressClass: kong
env:
database: "off"
router_flavor: expressions
proxy:
enabled: true
type: LoadBalancer
http:
enabled: true
servicePort: 80
tls:
enabled: true
servicePort: 443
admin:
enabled: true
type: ClusterIP
http:
enabled: true
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 1Gi
replicaCount: 2
CRD는 별도로 먼저 설치하는 것이 안전합니다. 차트에 CRD 설치를 맡기면 업그레이드 시 충돌이 날 수 있으므로, CRD는 명시적으로 관리하는 편이 운영상 깔끔합니다.
kubectl apply -f https://github.com/Kong/kubernetes-ingress-controller/releases/latest/download/all-in-one-dbless.yaml
values 파일이 준비되면 설치합니다.
helm install kong kong/ingress \
--namespace kong \
--values values-dbless.yaml
설치가 끝나면 게이트웨이 서비스의 외부 IP와 컨트롤러 상태를 확인합니다.
kubectl get pods -n kong
kubectl get svc -n kong
kubectl get ingressclass
IngressClass에 `kong`이 보이고 게이트웨이 서비스에 EXTERNAL-IP가 할당되었다면 트래픽을 받을 준비가 된 것입니다. 이후에는 앞에서 본 Ingress·HTTPRoute·KongPlugin 리소스를 적용해 라우팅과 정책을 구성하면 됩니다.
Declarative config와 GitOps
DB-less 모드의 가장 큰 매력은 모든 설정이 쿠버네티스 리소스로 표현되어 Git에 그대로 담긴다는 점입니다. 이는 GitOps와 자연스럽게 맞물립니다. Argo CD나 Flux로 매니페스트를 동기화하면, 게이트웨이 설정의 변경 이력과 롤백이 그대로 Git 워크플로 안에서 관리됩니다.
쿠버네티스 밖에서 Kong을 함께 쓰는 조직이라면 decK라는 도구도 알아 둘 만합니다. decK는 Kong의 declarative 설정을 코드로 관리하고, 현재 상태와 원하는 상태의 차이를 보여 주며(diff), 동기화하는 CLI입니다. KIC가 생성한 설정을 내보내(dump) 검증하거나, 환경 간 설정을 비교하는 데 유용합니다.
deck gateway dump --kong-addr http://localhost:8001 -o kong-state.yaml
deck gateway diff kong-state.yaml --kong-addr http://localhost:8001
다만 KIC와 decK를 동시에 같은 게이트웨이에 쓸 때는 주의가 필요합니다. DB-less 모드에서 단일 진실 공급원은 쿠버네티스 리소스여야 하므로, decK는 내보내기와 검증 용도로 제한하고, 설정 변경은 쿠버네티스 리소스를 통해서만 하는 규율을 지키는 것이 충돌을 막는 길입니다.
운영과 튜닝
프로덕션에서 KIC를 안정적으로 운영하려면 몇 가지 핵심 포인트를 챙겨야 합니다.
첫째, 데이터플레인의 수평 확장입니다. DB-less 모드의 게이트웨이는 무상태에 가깝기 때문에 replica를 늘리는 것만으로 처리량을 키울 수 있습니다. 다만 rate-limiting의 로컬 정책은 파드별로 한도를 따로 계산하므로, 정확한 전역 한도가 필요하면 Redis 정책으로 바꿔야 합니다.
둘째, 헬스체크와 프로브입니다. Kong은 상태 엔드포인트를 제공하므로, 이를 readiness와 liveness 프로브에 연결해 비정상 파드를 빠르게 격리해야 합니다. 또한 업스트림 헬스체크(active/passive)를 KongUpstreamPolicy로 설정해, 죽은 백엔드 파드로 트래픽이 가지 않도록 합니다.
셋째, 리소스와 워커 튜닝입니다. NGINX 워커 프로세스 수, 커넥션 한도, 타임아웃 같은 값은 트래픽 특성에 맞게 조정해야 합니다. 특히 업스트림 keepalive 커넥션 풀을 적절히 키우면, 매 요청마다 백엔드와 새 커넥션을 맺는 비용을 줄일 수 있습니다.
넷째, TLS와 인증서 관리입니다. cert-manager와 연동해 인증서 발급과 갱신을 자동화하는 것이 표준입니다. Ingress의 TLS 섹션이나 Gateway의 리스너에 인증서 시크릿을 연결하고, cert-manager가 Let's Encrypt 등으로 자동 갱신하도록 구성합니다.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-example-com-tls
namespace: default
spec:
secretName: api-example-com-tls
dnsNames:
- api.example.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
다섯째, 보안 경계입니다. Admin API는 절대로 외부에 노출하지 않아야 합니다. ClusterIP로 두거나 네트워크 정책으로 접근을 제한하고, DB-less 모드에서는 Admin API를 읽기 전용에 가깝게 운영하는 것이 안전합니다. ingress-nginx에서 반복적으로 문제가 됐던 "임의 설정 주입" 류의 취약점을 피하려면, 플러그인 설정을 신뢰할 수 있는 소스(Git, 검토된 매니페스트)로만 관리해야 합니다.
자주 만나는 함정과 트러블슈팅
운영 중에 자주 마주치는 문제들을 원인과 함께 정리했습니다.
첫째, IngressClass 누락입니다. Ingress에 `ingressClassName: kong`을 지정하지 않으면 KIC가 그 Ingress를 무시합니다. 라우팅이 전혀 동작하지 않는데 로그도 조용하다면 가장 먼저 이것을 의심해야 합니다. Gateway API에서는 GatewayClass의 `controllerName`이 KIC의 컨트롤러 이름과 정확히 일치하는지 확인합니다.
둘째, 플러그인 어노테이션 오타입니다. `konghq.com/plugins` 어노테이션에 적은 이름이 실제 KongPlugin 리소스 이름과 다르거나, 네임스페이스가 어긋나면 플러그인이 적용되지 않습니다. 플러그인이 안 걸리는 것처럼 보일 때는 KongPlugin 리소스의 이름과 네임스페이스, 그리고 어노테이션 문자열을 대조해야 합니다.
셋째, strip_path 혼란입니다. `konghq.com/strip-path`를 true로 두면 매칭된 경로 접두사가 제거되어 백엔드로 전달됩니다. 백엔드가 받는 경로가 예상과 다르다면 이 설정을 확인합니다. `/api`로 들어온 요청이 백엔드에 `/`로 도착하는지, `/api`로 도착하는지가 여기서 갈립니다.
넷째, 설정 반영 지연입니다. KIC는 변경을 감지해 게이트웨이에 동기화하는데, 대량 변경이나 큰 클러스터에서는 약간의 지연이 있을 수 있습니다. 변경이 반영되지 않은 것처럼 보일 때는 컨트롤러 로그에서 동기화 성공 여부와 마지막 동기화 시각을 확인합니다.
다섯째, declarative config 검증 실패입니다. KIC가 생성한 declarative 설정에 오류가 있으면(예: 잘못된 플러그인 config 스키마), 게이트웨이가 새 설정을 거부하고 마지막 정상 설정을 유지합니다. 즉 "잘못된 변경을 적용했는데 아무 일도 안 일어난" 것처럼 보일 수 있습니다. 이때는 컨트롤러 로그에서 검증 에러 메시지를 찾는 것이 핵심입니다.
진단에 유용한 명령들을 모아 두면 다음과 같습니다.
kubectl logs -n kong deploy/kong-controller -c ingress-controller --tail=200
kubectl describe ingress api-ingress -n default
kubectl get kongplugin -A
kubectl get kongconsumer -A
kubectl port-forward -n kong svc/kong-admin 8001:8001
마지막 명령으로 Admin API에 포트포워딩한 뒤, 게이트웨이가 실제로 들고 있는 라우트·서비스·플러그인 상태를 직접 조회하면, 쿠버네티스 선언과 실제 적용 사이의 간극을 가장 빠르게 좁힐 수 있습니다.
여섯째, 검증 웹훅(admission webhook) 거부입니다. KIC는 검증 웹훅으로 잘못된 플러그인 설정이나 중복 크리덴셜을 사전에 막을 수 있습니다. `kubectl apply`가 거부된다면 웹훅 메시지를 그대로 읽는 것이 가장 빠른 해결책입니다. 웹훅은 잘못된 설정이 게이트웨이까지 도달하기 전에 막아 주는 안전망이므로, 비활성화하기보다 메시지를 해석해 고치는 것이 바람직합니다.
마치며
KIC는 단순한 Ingress 컨트롤러가 아니라, 쿠버네티스 네이티브한 선언을 풀스택 API Gateway로 연결하는 다리입니다. Ingress API가 동결되고 Gateway API가 표준의 자리를 가져간 2026년의 지형에서, KIC는 두 표준을 모두 지원하면서 플러그인 생태계라는 강력한 차별점을 제공합니다.
도입을 고민한다면 다음 순서를 권합니다. 먼저 DB-less 모드를 기본값으로 삼아 운영 복잡도를 낮추고, 설정은 모두 쿠버네티스 리소스로 표현해 GitOps에 태웁니다. 인증·레이트리밋·옵저버빌리티 같은 핵심 기능은 처음부터 플러그인으로 깔끔하게 분리해 백엔드를 가볍게 유지합니다. 신규 라우팅은 Gateway API의 HTTPRoute로 표현하되, 기존 Ingress 자산은 같은 컨트롤러 아래에서 병행 운영하며 점진적으로 이전합니다.
무엇보다 중요한 것은 "어노테이션에 모든 것을 욱여넣던 시대"에서 "구조화된 CRD와 표준 Gateway API로 정책을 표현하는 시대"로 넘어가는 흐름을 이해하는 것입니다. Kong은 그 전환을 비교적 매끄럽게 밟아 갈 수 있는 도구이며, API Gateway가 필요한 조직이라면 진지하게 검토할 가치가 충분합니다.
참고 자료
- Kong Ingress Controller 공식 문서: https://docs.konghq.com/kubernetes-ingress-controller/
- Kong Gateway 공식 문서: https://docs.konghq.com/gateway/
- Kong 플러그인 허브: https://docs.konghq.com/hub/
- Kong KIC GitHub 저장소: https://github.com/Kong/kubernetes-ingress-controller
- Kubernetes Ingress 개념 문서: https://kubernetes.io/docs/concepts/services-networking/ingress/
- Gateway API 공식 문서: https://gateway-api.sigs.k8s.io/
- ingress-nginx 문서: https://kubernetes.github.io/ingress-nginx/
- cert-manager 공식 문서: https://cert-manager.io/docs/
- decK 문서: https://docs.konghq.com/deck/
- Kong Helm 차트 저장소: https://github.com/Kong/charts
현재 단락 (1/400)
쿠버네티스에 서비스를 올리고 나면 곧바로 마주치는 질문이 있습니다. "외부 트래픽을 어떻게 받아서 어디로 보낼 것인가." 가장 표준적인 답은 Ingress 리소스이고, 그 구현체로...