EKS – Kubernetes Ingress

Ingress가 필요한 이유

Pod 접근의 한계

Kubernetes 클러스터가 구성되어 있다고 가정해보자. 컨트롤 플레인이 하나 있고, 워커 노드가 2대 실행되고 있다. 각 워커 노드에 Pod가 하나씩 배포되어 있는 상황이다

사용자가 Pod 안에서 실행 중인 애플리케이션의 데이터를 받으러면 어떻게 해야 할까? Pod로 직접 요청을 보내는 것은 불가능하다. Pod는 클러스터 내부에서도 격리되어 있기 때문이다. 따라서 사용자는 반드시 Service를 통해서만 Pod에 접근할 수 있다

Service 타입별 특성과 한계

Service로 요청을 보내려면 사용자가 접근할 수 있는 IP가 필요하다. 워커 노드는 물리적인 컴퓨터이므로 IP를 할당할 수 있지만, 사용자가 특정 워커 노드의 IP를 직접 바라보고 요청을 보내는 것은 적절하지 않다. 최종 목적지는 Service를 통해 Pod로 가는 것이기 때문이다

그래서 AWS에서는 Load Balancer라는 요소를 제공한다. 로드 밸런서를 생성하면 퍼블릭 IP(예: 100.100.100.100)가 할당되고, 사용자는 이 로드 밸런서를 통해 Service에 접근하게 된다.

Service 타입 중 LoadBalancer 타입을 선택하면 로드 밸런서가 자동으로 생성되고, 사용자는 해당 엔드포인트를 통해 Pod에 도달할 수 있다. 하지만 이 아키텍처에는 심각한 단점이 있다

  • 비용 증가: 서비스 개수만큼 로드 밸런서가 필요하며, AWS 로드 밸런서는 과금 대상이다
  • 엔트포인트 관리 복잡: 각 로드 밸런서마다 엔트포인트가 달라져 프론트엔드에서 관리가 어려워진다
  • 확장성 저하: 새로운 서비스 추가 시마다 로드 밸런서 생성이 필요하다

Ingress의 개념과 특성

Ingress는 위의 문제를 해결하기 위한 Kubernetes 리소스이다. 하나의 로드 밸런서만 두고, Ingress가 URL 패턴에 따라 여러 Service로 분기 처리를 해준다

Ingress의 두 가지 핵심 특성

URL 패턴 기반 라우팅

사용자가 server.abc.com/order-service로 요청하면 주문 서비스(S1)로, server.abc.com/member-service로 요청하면 회원 서비스(S2)로 라우팅된다

server.abc.com/order-service  → Service 1 (주문)
server.abc.com/member-service → Service 2 (회원)
server.abc.com/payment-service → Service 3 (결제)
도메인 기반 분기

Ingress는 도메인을 기반으로 동작한다. 서로 다른 목적의 서비스들을 도메인으로 분리할 수 있다. 예를 들어, 핵심 비즈니스 서버와 모니터링 서버만 분리하고 싶다면

server.abc.com     → Ingress 1 → 핵심 비즈니스 서비스들
monitoring.abc.com → Ingress 2 → 모니터링 서비스들 (Prometheus, Grafana 등)

이렇게 로드 밸런서는 하나만 유지하면서, 도메인에 따라 다른 Ingress로 라우팅하고, 각 Ingress 내에서는 URL 패턴으로 Service를 분기할 수 있다

Ingress Controller의 역할

Ingress vs Ingress Controller

IngressIngress Controller
순수 Kubernetes 리소스 (kind: Ingress)여러 리소스의 집합체
라우트 규칙 정의실제 라우팅 수행
kubectl apply로 생성별도 설치 필요
도메인별로 여러 개 가능클러스터당 하나면 충분

핵심 포인트: Ingress는 “어떤 URL 패턴이 어떤 Service로 가야 하는지”라는 규칙만 정의하고, 실제로 트래픽을 라우팅하는 것은 Ingress Controller가 담당한다

Ingress Controller 설치 시 일어나는 일

  • AWS의 Network Load Balancer가 자동으로 생성됨
  • 로드 밸런서의 DNS 주소가 할당됨
  • 이 DNS를 Route53에서 원하는 도메인과 매핑

전체 트래픽 흐름

사용자 요청 (server.k8s.shop/order-service)
    ↓
Route53 (도메인 → 로드 밸런서 IP 매핑)
    ↓
AWS Load Balancer
    ↓
Ingress Controller Pod (도메인 분석 → 해당 Ingress 선택)
    ↓
Ingress (URL 패턴 분석 → 해당 Service 선택)
    ↓
Service
    ↓
Pod (실제 애플리케이션)

Ingress 구성하기

사전 준비

Nginx Deployment가 실행 중인지 확인한다

kubectl get pod -n hyeok

Pod 2대가 Running 상태인지 확인한다

Ingress Controller 설치

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/aws/deploy.yaml

참고: 실무에서는 이 yaml 파일을 다운로드하여 필요에 따라 커스터마이징한 후 관리하는 것이 좋다. 인터넷 상의 파일은 언제든 변경될 수 있기 때문이다

  • namespace/ingress-nginx
  • deployment/ingress-nginx-controller
  • service/ingress-nginx-controller
  • 기타 RBAC 관련 리소스들

AWS 로드 밸런서 확인

AWS Console → EC2 → 로드 밸런싱 → 로드 밸런서에서 새로 생성된 Network Load Balancer를 확인할 수 있다. 상태가 “활성”이 될 때까지 잠시 기다린다

Route53 레코드 설정

  • AWS Console → Route53 → 호스팅 영역 → 해당 도메인 선택
  • “레코드 생성” 클릭
  • 다음과 같이 설정
항목설정값
레코드 이름server (서브도메인)
레코드 유형A – IPv4 주소
별칭활성화
트래픽 라우팅 대상Network Load Banalcer에 대한 별칭
리전아시아 태평양(서울)
로드 밸런서생성된 로드 밸런서 선택
A 레코드 vs CNAME
  • A 레코드 + 별칭: 같은 AWS 계정의 리소스를 매핑할 때 권장 (실수 확률 감소)
  • CNAME: 다른 계정의 도메인이나 외부 도메인을 매핑할 때 사용

레코드 생성 후 상태가 PENDING에서 INSYNC로 변경되면 설정 완료이다 (약 1분 소요)

Ingress 리소스 생성

ingress_nginx.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: hyeok
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1  # 첫 번째 prefix 제거
spec:
  rules:
  - host: server.hyeok4444.shop  # 설정하려는 도메인
    http:
      paths:
      - path: /hyeok/  # hyeok으로 시작하는 모든 URL 요청
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

주요 설정 설명

  • kubernetes.io/ingress.class: nginx: 이 Ingress가 NGINX 기반 Ingress Controller에 의해 처리됨을 명시
  • host: 이 Ingress가 처리할 도메인
  • path: URL 패턴 (정규표현식 사용 가능)
  • rewrite-target: /$1: 첫 번째 prefix를 제거하고 실제 서비스로 전달
rewrite-target이 필요한 이유

사용자가 server.hyeok4444.shop/hyeok/으로 요청하면, /hyeok/ 경로가 그대로 Nginx Pod에 전달된다. 하지만 Nginx는 /hyeok/이라는 경로를 알지 못한다. 따라서 rewrite-target: /$1을 통해 첫 번째 prefix(/hyeok/)를 제거하고 /만 전달하면 Nginx의 기본 홈페이지가 응답한다

Ingress 적용 및 확인

# Ingress 적용
kubectl apply -f ingress_nginx.yml

# Ingress 확인
kubectl get ingress -n hyeok
```

출력 예시:
```
NAME            CLASS    HOSTS                   ADDRESS                                    PORTS   AGE
nginx-ingress   <none>   server.hyeok4444.shop   a9026ba...elb.ap-northeast-2.amazonaws.com   80      77s

테스트

http://server.hyeok4444.shop/hyeok/ → Nginx 환영 페이지 출력

http://server.hyeok4444.shop/pitt/ → 404 Not Found

404 에러가 발생하면 “404 Not Found nginx”라고 표시되는데, 이는 요청이 Ingress Controller Pod에서 멈춘 상태이다. /pitt/라는 path가 Ingress에 정의되어 있지 않아 Service까지 도달하지 못한 것이다.

트러블 슈팅

Pod 상태 확인

kubectl get pods -n hyeok

Pod가 Running 상태가 아니라 Pending, Terminating 등의 상태라면 문제가 있는 것이다

로그 확인

kubectl logs <pod-name> -n hyeok

애플리케이션 레벨의 에러는 로그에서 확인할 수 있다

Pod 상세 정보 확인

kubectl describe pod <pod-name> -n hyeok

Kubernetes가 추적하는 Pod의 상태와 이벤트를 확인할 수 있다. 리소스 부족, 이미지 Pull 실패 등의 문제는 여기서 확인된다

리소스 정리

실습 후 리소스를 삭제하려면

# Ingress 삭제
kubectl delete -f ingress_nginx.yml

# Deployment 삭제
kubectl delete -f nginx_deployment.yml

# Ingress Controller 삭제 (필요시)
kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/aws/deploy.yaml

서비스가 하나뿐인 경우

만약 서비스가 하나뿐이라서 URL 패턴 분기가 필요 없다면, 설정을 단순화할 수 있다

spec:
  rules:
  - host: server.hyeok9244.shop
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

이 경우 rewrite-target 설정도 필요 없다. 들어오는 URL을 그대로 서비스로 전달하면 되기 때문이다

URL 패턴 분기는 주로 MSA(Microservices Architecture)에서 사용된다. 모놀로식 서비스를 여러 개의 마이크로서비스로 분리했을 때, 하나의 엔드포인트로 여러 서비스에 접근해야 하는 상황에서 유용하다

핵심 요약

  • Ingress: 라우팅 규칙을 정의하는 Kubernetes 리소스
  • Ingress Controller: 실제 라우팅을 수행하는 컴포넌트, 설치 시 로드 밸런서 자동 생성
  • 도메인 기반: 하나의 로드 밸런서로 여러 도메인 처리 가능
  • URL 패턴 기반: 하나의 Ingress 내에서 여러 Service로 분기 가능
  • Route53: 로드 밸런서 DNS와 사용자 도메인을 매핑

출처 – eks를 활용한 spring 운영서버 배포(feat. devops의 모든것)