Kubernetes - Ingress 테스트용 애플리케이션 설치 및 설정 테스트

2026. 1. 17. 11:17·Container & DevOps

Ingress의 주요 목적

인그레스의 핵심 목적은 사용자가 접속한 URL의 호스트 또는 경로에 따라 서로 다른 백엔드 서비스로 트래픽을 분기하는 것이다.
이를 테스트하기 위해 서로 다른 4개의 애플리케이션을 준비한다.

구성 대상은 다음과 같다.

  • coffee
  • tea
  • juice
  • water

각 애플리케이션은 서로 다른 Deployment + Service로 구성된다. 모든 파드는 동일한 테스트 이미지인 nginxdemos/nginx-hello:plain-text를 사용한다.

해당 이미지의 특징은 요청을 처리한 파드의 호스트네임을 응답으로 출력한다는 점이다.

따라서 인그레스 분기가 정상 동작하는지 쉽게 확인할 수 있다.

Manifest 작성

서로 다른 4개의 디플로이먼트와 서비스 YAML 파일을 다음과 같이 작성한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
        - name: coffee
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
        - name: tea
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: tea
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: juice
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: juice
  template:
    metadata:
      labels:
        app: juice
    spec:
      containers:
        - name: juice
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: juice-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: juice
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: water
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: water
  template:
    metadata:
      labels:
        app: water
    spec:
      containers:
        - name: water
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: water-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: water

각 서비스는 다음 공통 구조를 가진다.

  • type: ClusterIP
  • port: 80
  • targetPort: 8080
  • selector: app 이름

다음과 같은 역할을 수행한다.

  • coffee-svc → app=coffee 파드로 전달
  • tea-svc → app=tea 파드로 전달
  • juice-svc → app=juice 파드로 전달
  • water-svc → app=water 파드로 전달

deployment / services 생성

위에서 작성한 매니패스트를 이용하여 default 네임스페이스에 오브젝트를 생성해준다.

kubectl apply -f cafe-svc-deploy.yml

위와 같이 정상적으로 생성된 것을 확인할 수 있다.

 

또한 busybox 파드를 생성하여 개별 서비스 이름으로 접속 테스트를 해본다.

kubectl run busybox --image=busybox:1.28 --restart=Never -- sleep 1d
kubectl exec -it busybox -- sh

 

아래와 같이 각 요청에 대한 응답으로 파드 이름이 출력되는 것을 확인할 수 있다.

wget -O- coffee-svc
wget -O- water-svc

Traefik CRD를 이용한 Ingress 설정의 이해

쿠버네티스에서 Ingress는 외부 트래픽을 내부 서비스로 전달하기 위한 L7 라우팅 개념이다. 일반적으로는 Kubernetes 기본 Ingress 리소스를 사용하지만, Traefik은 이와 다른 접근 방식을 사용한다.
Traefik은 CRD(Custom Resource Definition) 기반의 Ingress 설정 방식을 제공한다.

cf. CRD란 사용자가 임의로 자신이 필요한 쿠버네티스 API 리소스를 모아서 원하는 기능을 구현하는 쿠버네티스 API 확장 기능이다.

Traefik이 왜 CRD 기반 Ingress를 제공하는지, 그리고 IngressRoute가 어떤 원리로 동작하는지 살펴보자.

기존 Kubernetes Ingress의 구조적 한계

Kubernetes 기본 Ingress는 하나의 리소스에 모든 라우팅 설정을 담는다.

  • 도메인 조건
  • 경로 조건
  • TLS 설정
  • 리다이렉션
  • 인증 관련 설정

이 모든 기능을 annotation에 의존하여 확장한다. 그 결과 Ingress YAML은 다음과 같은 문제를 가진다.

  • 설정이 길고 복잡하다
  • annotation이 컨트롤러마다 다르다
  • 가독성이 떨어진다
  • 라우팅 구조를 한눈에 이해하기 어렵다

즉, Ingress는 표준 리소스이지만 복잡한 트래픽 제어에는 적합하지 않다. 따라서 Traefik은 위 문제들을 회피하기 위해 CRD 기반의 Ingress 설정 방식을 사용하는 것이다. 그러면 다음 내용들을 쉽게 설정할 수 있다.

 

  • 복잡한 라우팅 규칙
  • Host + Path 조합
  • EntryPoint 분기
  • TLS 설정

 

Traefik IngressRoute 기본 구조

IngressRoute의 핵심 구조는 다음 3단계이다.

EntryPoints → Routes(Routers) → Services
  • EntryPoint는 Traefik이 외부 요청을 처음 받는 포트이다.
    • ex. web -> 80, websecure -> 443
  • Router는 들어온 요청을 처리할지 말지를 판단하는 규칙이다.
    • 도메인이 www.myweb.com 이고, URL 경로가 /juice로 시작하는 요청만이 Router가 처리한다.
  • Service는 Router가 선택한 요청을 어디로 보낼지를 정의한다.
    • services:
        - name: juice-svc
          port: 80

IngressRoute CRD 설정

IngressRoute에 대한 YAML 파일을 다음과 같이 작성해준다.

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: coffee-ingressroute
  namespace: default
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`coffee.myweb.com`)
    kind: Rule
    services:
    - name: coffee-svc
      port: 80
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: tea-ingressroutetls
  namespace: default
spec:
  entryPoints:
  - websecure
  routes:
  - match: Host(`tea.myweb.com`)
    kind: Rule
    services:
    - name: tea-svc
      port: 80
  tls:
    certResolver: myresolver
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: juice-ingressroutetls
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`www.myweb.com`) && PathPrefix(`/juice`)
    kind: Rule
    services:
    - name: juice-svc
      port: 80
  tls:
    certResolver: myresolver
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: water-ingressroutetls
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`www.myweb.com`) && PathPrefix(`/water`)
    kind: Rule
    services:
    - name: water-svc
      port: 80
  tls:
    certResolver: myresolver
  • apiVersion
    • 이 리소스는 Kubernetes 기본 리소스가 아니다
    • Traefik이 정의한 CRD(Custom Resource Definition) 이다
    • Traefik 컨트롤러만 이 리소스를 해석하고 처리한다
  • kind
    • IngressRoute는 Traefik에서 말하는 Router 리소스이다.
    • 기존 Kubernetes Ingress와 달리, 하나의 Ingress에 모든 규칙을 넣지 않고 라우팅 단위 하나당 IngressRoute 하나를 만든다
    • coffee, tea, juice, water 각각은 완전히 독립된 라우터이다.
  • spec.entryPoints
    • entryPoints:
      - web 
      • Traefik이 80 포트(HTTP) 로 받은 요청만 이 라우터에서 처리한다
      • HTTPS(443) 요청은 아예 이 IngressRoute에 도달하지 않는다
    • entryPoints:
      - websecure
      • Traefik이 443 포트(HTTPS) 로 받은 요청만 처리한다
      • HTTP 요청은 이 라우터와 무관하다
  • routes.match
    • match: Host(`coffee.myweb.com`)
      • HTTP 요청의 Host 헤더가
      • 정확히 coffee.myweb.com 인 경우만
      • 이 Router가 요청을 처리한다
    • match: Host(`tea.myweb.com`)
      • HTTPS 요청 중 Host가 tea.myweb.com 인 경우만 처리한다
    • match: Host(`http://www.myweb.com`) && PathPrefix(`/juice`)
    • match: Host(`http://www.myweb.com`) && PathPrefix(`/water`)
      • 도메인은 동일하다 (www.myweb.com)
      • 경로(/juice, /water) 기준으로 서비스 분기한다
      • PathPrefix이므로 /juice/aaa 도 포함된다
      • 하나의 도메인 안에서 URL 경로 기준으로 서비스 라우팅을 수행한다
  • kind: Rule
    • match 구문이 Traefik Rule DSL 문법이라는 의미이다
    • 거의 항상 Rule로 고정된다
  • services
    • services:
      - name: coffee-svc
        port: 80
      • Router 조건을 만족한 요청을 Kubernetes Service coffee-svc 로 전달한다.
      • Service가 바라보는 Pod로 트래픽이 전달된다.
  • tls
    • tls:
        certResolver: myresolver
      • Traefik은 기본 설정으로 lets-encrypt 인증서를 제공한다.
      • 이 Router는 HTTPS 전용이다
      • TLS 종료를 Traefik이 담당한다
      • 인증서는 myresolver 를 통해 동적으로 획득한다

Traefik CRD 설치

쿠버네티스는 기본적으로 다음만 알고 있다.

  • Pod
  • Service
  • Deployment
  • Ingress 등

하지만 IngressRoute 는 쿠버네티스 기본 리소스가 아니라서 따로 CRD로 추가해 주어야만 사용할 수 있다.

아래 명령어를 통해 Traefik 공식 CRD 파일을 적용한다.

kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
  • IngressRoute
  • Middleware
  • TraefikService
  • TLSOption
  • TLSStore

등을 Traefik CRD 전체를 클러스터에 등록한다.

다음과 같이 정상적으로 설치되어있는지 확인한다.

kubectl get crd | grep traefik

위와 같이 정상적으로 설치된 것을 확인할 수 있다.

 

IngressRoute 리소스 생성

아래 명령어를 통해 IngressRoute 리소스를 생성해준다.

kubectl apply -f cafe-crd-ingressroute.yml

 

아래와 같이 성공적으로 리소스가 생성되었는지 확인한다.

kubectl get ingressroute

총 4개의 서로 다른 IngressRoute 가 생성되었고, 각각 다음 기준으로 트래픽을 분리한다.

  • Host 기반 라우팅
    • coffee.myweb.com
    • tea.myweb.com
  • Host + Path 기반 라우팅
    • www.myweb.com/juice
    • www.myweb.com/water

외부 접속을 위한 /etc/hosts 설정

공인 도메인을 사용하지 않고 사설 도메인 이름을 테스트하기 때문에, 클라이언트 PC의 /etc/hosts 파일에 도메인과 IP를 직접 매핑한다.

외부 사용자는 Traefik ingress-controller를 통해 접속하므로 Traefik LoadBalancer 서비스의 EXTERNAL-IP 를 기준으로 설정한다.

먼저, Traefik 서비스를 먼저 확인한다.

kubectl get svc -n traefik

EXTERNAL-IP를 확인하고, 다음과 같이 /etc/hosts 파일을 설정한다.

vi /etc/hosts
10.0.2.62  www.myweb.com
10.0.2.62  coffee.myweb.com
10.0.2.62  tea.myweb.com

curl 명령어로 인그레스가 정상적으로 서비스를 분기하는지 확인한다.

curl http://coffee.myweb.com
curl http://tea.myweb.com
curl https://tea.myweb.com -k
curl https://www.myweb.com/juice -k
curl https://www.myweb.com/water -k

위와 같이 정상적으로 서비스가 분기되는 것을 확인할 수 있다. 

이처럼 Traefik IngressRoute CRD를 통해 인그레스 리소스를 쉽고 효율적으로 설정할 수 있다.

 

IngressRoute는 관리자 페이지에서도 확인 가능하다.

http://localhost:8080/dashboard/#/

관리자 페이지에서 [HTTP Routers] -> [Explore]를 선택하면 추가한 가상 호스트와  경로에 따른 개별 Rule을 확인할 수 있다. 해당 관리자 페이지로 정상 동작 여부와 설정 내역을 확인할 수 있다.

 

또한, 다음과 같이 같은 서비스 내 서로 다른 파드로 부하 분산되는 것을 확인할 수 있다.

전체 흐름 정리

Traefik 인그레스 컨트롤러로 부터 트래픽이 처리되는 과정은 아래와 같이 정리할 수 있다. 

curl https://www.myweb.com/juice -k
사용자
 → DNS
 → LoadBalancer IP
 → NodePort
 → service/traefik
 → Traefik Pod
 → EntryPoint(websecure)        [values.yml]
 → Router(match 조건)           [IngressRoute]
 → juice-svc
 → juice Pod
cf. 프로세스가 직접 listen 하는 포트는 netstat/ss 로 확인 가능하지만, NodePort·Service 트래픽은 kube-proxy가 커널 레벨에서
DNAT 또는 IPVS 규칙으로 처리하므로 iptables, nft, ipvsadm 등으로 확인해야 한다.(kube-proxy 모드 확인 필수 - kubectl get cm kube-proxy -n kube-system -o yaml | grep mode)

 

cf. values.yaml은 Traefik Service로부터 들어온 트래픽을 어느 EntryPoint에서 수신할지를 정의하고, ingressRoute.yml은 해당 EntryPoint로 들어온 트래픽을 어떤 Service로 전달할지를 정의한다.

 

Reference

  • https://kubernetes.io/ko/docs/home/
  • 이정훈, ⌜24단계 실습으로 정복하는 쿠버네티스⌟, 위키북스, 2022, 492쪽
'Container & DevOps' 카테고리의 다른 글
  • kubernetes - Storage/OpenEBS
  • kubernetes - 사용자 SSL/TLS 인증서 적용
  • Kubernetes - Traefik 인그레스 컨트롤러 구축
  • Kubernetes - 노드 장애 시 서비스 다운시간 측정
SummerToday
SummerToday
summertoday 님의 블로그 입니다.
  • SummerToday
    SummerToday
    SummerToday
  • 전체
    오늘
    어제
  • 인기 글

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
    • 관리자
    • 분류 전체보기 (62)
      • OS & Network (4)
      • Cloud (11)
      • Container & DevOps (41)
      • Database (4)
      • Develop (0)
      • IaC (2)
  • 태그

    tailscale
    gitops
    openebs
    argocd
    cloud
    MariaDB
    EIP
    CI/CD
    Galera Cluster
    점프 계정
    AmazonSNS
    s2s vpn
    K8S
    Eni
    Grafana
    aws
    계정 관리
    container
    CloudWatch
    Kubernetes
  • hELLO· Designed By정상우.v4.10.3
SummerToday
Kubernetes - Ingress 테스트용 애플리케이션 설치 및 설정 테스트
상단으로

티스토리툴바