cloudwithbass

[Kubernetes] ★Ingress란?, alb-ingress-controller 사용하기 본문

Kubernetes

[Kubernetes] ★Ingress란?, alb-ingress-controller 사용하기

여영클 2024. 8. 11. 14:20

목차


    Ingress

    • Ingress는 클러스터 외부에서 오는 트래픽을, 클러스터 내부의 Service로 라우팅하기 위한 쿠버네티스 리소스입니다.
    • Ingress 뿐만 아니라, Service의 유형 중 Nodeport와 LoadBalancer 또한 클러스터 외부의 트래픽을 처리할 수 있습니다.
    • 그렇다면 Ingress는 Service와 같은 역할을 하는 듯 보이는데, 왜 Ingress를 사용해야 할까요?

    Service만 사용할 경우 문제점

    Service는 포트 포워딩을 이용해 클러스터 외부에서 오는 트래픽을 처리합니다.

    예를 들어, 아래 그림을 예시로 들어보겠습니다.

    Service만 이용할 경우

     

    위 그림에서 Service 1은 70번 포트를 POD의 7000번 포트로 포워딩하고, Service 2는 80번 포트를 POD의 8000번 포트로 포워딩합니다. 

     

     

    물론 위 그림의 구성으로도 잘 동작하겠지만 다음과 같은 문제점들이 있습니다.

    1. 각 서비스가 개별적으로 외부에 노출되면 포트 번호를 관리하기 어렵습니다.
    2. 서비스가 많아질수록 노출해야 하는 포트의 수가 증가하고, 그만큼 포트 충돌의 가능성도 커집니다.
    3. 게다가 LoadBalancer 유형의 Service를 사용하는 경우, 각 서비스마다 클라우드 공급자가 로드 밸런서를 프로비저닝하기 때문에 이를 관리하기도 어렵고, 비용도 증가할 수 있습니다.

    해결 방법은 Ingress

    ingress를 이용하면 위 문제를 해결할 수 있습니다.

    다음 그림처럼 Ingress는 일종의 proxy 역할을 합니다.

    사용자가 ingress에 요청을 보내면, ingress는 요청된 경로에 맞게 트래픽을 적절 서비스로 라우팅합니다.

    예를 들어, 사용자가 '/Service1' 경로에 접근하면 Ingress 그 요청을 Service 1로 라우팅합니다.

    따라서 더이상 사용자는 컨테이너의 포트 번호를 노출할 필요가 없으며, 도메인과 경로만으로 클러스터 외부에서 컨테이너에 접근할 수 있게 됩니다.

     

    게다가 Ingress는 HTTPS를 지원하므로 SSL/TLS를 사용할 수 있습니다.


    Ingress Controller

    Ingress를 사용하기 위해선 반드시 Ingress Controller가 필요합니다.

    Ingress Controller는 API Server에서 Ingress event를 감시하고, 트래픽을 적절하게 라우팅합니다.

     

    Ingress Controller의 종류는 Nginx ingress controler, Traefik 등이 있으며, 저는 실습에서 alb-ingress-controller를 사용할 것입니다.


    실습

    실습에서 구현해볼 아키텍처입니다.

    /nginx1 경로의 트래픽은 svc-ngxin1 서비스로 라우팅되어 nginx1 POD로 이동합니다.

    /nginx2 경로의 트래픽은 svc-nginx2 서비스로 라우팅되어 nginx2 POD로 이동합니다.


    1. Ingress Controller 설치

    AWS LoadBalancer Controller 설치 가이드 문서에 따라 AWS LoadBalancer Controller를 배포합니다.


    2. Pod, Service, Ingress 배포

    Deployment

    nginx는 80번 포트를 사용하기 때문에 둘 다 containerPort를 80으로 설정했습니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-nginx1
      labels:
        app: deployment-nginx1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx1
      template:
        metadata:
          labels:
            app: nginx1
        spec:
          containers:
          - name: nginx1
            image: nginx:latest
            ports:
              - containerPort: 80
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-nginx2
      labels:
        app: deployment-nginx2
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx2
      template:
        metadata:
          labels:
            app: nginx2
        spec:
          containers:
          - name: nginx2
            image: nginx:latest
            ports:
            - containerPort: 80

     

    Service

    svc-nginx1은 80번 포트로 들어온 트래픽을, label이 app: nginx1인 Pod의 80번 포트로 라우팅합니다.

    svc-nginx2는 90번 포트로 들어온 트래픽을, label이 app: nginx2인 Pod의 80번 포트로 라우팅합니다.

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-nginx1
    spec:
      selector:
        app: nginx1
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      type: NodePort
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: svc-nginx2
    spec:
      selector:
        app: nginx2
      ports:
      - port: 90
        targetPort: 80
        protocol: TCP
      type: NodePort

     

    Ingress

    annotations 부분에선 인터넷 접근을 허용하고, 서비스가 Nodeport를 사용하기 때문에 ALB가 트래픽을 전달할 대상을 IP로 설정했습니다.

    spec.rules.http.paths.pathType이 Prefix입니다. 따라서 /nginx1로 시작하는 모든 경로는 svc-nginx1로 라우팅되고, /nginx2로 시작하는 모든 경로는 svc-nginx2로 라우팅됩니다.

     

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
        - http:
            paths:
              - pathType: Prefix
                path: /nginx1
                backend:
                  service:
                    name: svc-nginx1
                    port:
                      number: 80
              - pathType: Prefix
                path: /nginx2
                backend:
                  service:
                    name: svc-nginx2
                    port:
                      number: 90

     

     

    AWS 콘솔에서 로드 밸런서를 확인하면 성공적으로 프로비저닝 된 것을 확인할 수 있습니다.

     


    3. 컨테이너 설정

    Nginx1과 Nginx2 Pod를 구분하기 위해 nginx 컨테이너를 실행해서 index.html 내용을 수정할 겁니다.

     

    kubectl get pod로 nginx pod의 이름을 확인하고, 그 pod의 /bin/bash를 실행해줍니다.

     

    kubectl exec -it {podname} -- /bin/bash 명령으로 컨테이너의 bash를 사용할 수 있습니다.

    kubectl exec -it deployment-nginx1-67d5c7c44b-lshm6 -- /bin/bash

     

    컨테이너로 들어가 아래 명령을 실행합니다.

    vi 패키지를 설치하고, index.html의 위치를 찾는 명령입니다.

    apt-get update
    apt-get install -y vim
    find -name index.html

    /usr/share/nginx/html/ 위치에 index.html이 있음을 확인했습니다.

    nginx는 기본적으로 이 index.html을 반환합니다.

     

    하지만 /nginx1 경로에 접속할 경우, 별도의 설정이 없다면 nginx1이라는 서브 디렉토리를 찾으려 할 것입니다.

    만약 해당 디렉토리와 그 안에 index.html 파일이 존재하지 않으면, Nginx는 404 Not Found 오류를 반환합니다.

    따라서 /usr/share/nginx/html/에 nginx 폴더를 만들겠습니다.

     

    cd /usr/share/nginx/html/
    mkdir nginx1
    cp index.html nginx1/

     

    이제 처음에 설치한 vi 패키지를 이용해 /usr/share/nginx/html/nginx1/index.html에서  <h1>의 내용을 바꿔보겠습니다.

    vi nginx1/index.html

    저는 <body>의 <h1>을 'Hi! this is 'nginx1'.'이라고 변경했습니다. 

     

    같은 방식으로 nginx2의 컨테이너의 <h1>도 바꿔줍니다.

    이번엔 'This 'nginx2'. have a nice day.'로 변경했습니다.

     

     

    이제 alb의 DNS에서 /nginx1과 /nginx2 경로에 접속해보겠습니다.

     

     

    /nginx1 경로
    /nginx2 경로

     

     

     

     

    'Kubernetes' 카테고리의 다른 글

    [Kubernetes] DNS Deep Dive in Kubernetes with CoreDNS  (1) 2024.11.17
    [K8S] EKS Basics  (0) 2024.07.29
    [k8s] Kubernetes Basics  (0) 2024.07.28
    [k8s] 로컬에 kubectl 환경 구성하기  (0) 2024.07.27