Kubernetes

[ Kans 3 Study - 6w ] 2. Ingress

su''@ 2024. 10. 12. 23:16
CloudNetaStudy - Kubernets Networtk 3기 실습 스터디 게시글입니다.

 

Ingress - 링크

 

클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) - Web Proxy 역할

  • HTTP/HTTPS 요청 트래픽을 부하분산
  • 카나리 배포 지원
    출처 - 김태민 기술 블로그 https://kubetm.github.io/k8s/08-intermediate-controller/ingress/
  • 경로 기반, 호스트 기반 라우팅 지원
  • SSL/TLS 종료를 지원
    • 외부 → 인그레스 컨트롤러 : https 접속
    • 인그레스 컨트롤러 파드   (내부망)목적지 파드 : http 통신 
전제 조건

- 인그레스 컨트롤러가 있어야 인그레스를 충족할 수 있다. 인그레스 리소스만 생성한다면 효과가 없다.
- ingress-nginx와 같은 인그레스 컨트롤러를 배포해야 할 수 있다.
- 인그레스 컨트롤러는 참조 사양이 맞아야 한다. 실제로, 다양한 인그레스 컨트롤러는 조금 다르게 작동한다.

 

  • 인그레스 컨트롤러 : 인그레스의 실제 동작 구현은 인그레스 컨트롤러(Nginx, Kong 등)가 담당

 

 

[ Ingress 를 통한 통신 흐름 ]

Nginx 인그레스 컨트롤러  : 외부에서 인그레스로 접속 시 Nginx 인그레스 컨트롤러 파드로 인입되고, 이후 애플리케이션 파드의 IP로 직접 통신(서비스를 경유하지 않는다.)

 

클러스터 내부를 외부에 노출 - 발전 단계
더보기
  1. 파드 생성 : K8S 클러스터 내부에서만 접속
  2. 서비스(Cluster Type) 연결 : K8S 클러스터 내부에서만 접속
    • 동일한 애플리케이션의 다수의 파드의 접속을 용이하게 하기 위한 서비스에 접속
  3. 서비스(NodePort Type) 연결 : 외부 클라이언트가 서비스를 통해서 클러스터 내부의 파드로 접속
    • 서비스(NodePort Type)의 일부 단점을 보완한 서비스(LoadBalancer Type) 도 있습니다!
  4. 인그레스 컨트롤러 파드를 배치 : 서비스 앞단에 HTTP 고급 라우팅 등 기능 동작을 위한 배치
    • 인그레스(정책)이 적용된 인그레스 컨트롤러 파드(예. nginx pod)를 앞단에 배치하여 고급 라우팅 등 기능을 제공
  5. 인그레스 컨트롤러 파드 이중화 구성 : Active(Leader) - Standby(Follower) 로 Active 파드 장애에 대비
  6. 인그레스 컨트롤러 파드 외부에 노출 : 인그레스 컨트롤러 파드를 외부에서 접속하기 위해서 노출(expose)
    • 인그레스 컨트롤러 노출 시 서비스(NodePort Type) 보다는 좀 더 많은 기능을 제공하는 서비스(LoadBalancer Type)를 권장합니다 (80/443 포트 오픈 시)
  7. 인그레스와 파드간 내부 연결의 효율화 방안 : 인그레스 컨트롤러 파드(Layer7 동작)에서 서비스 파드의 IP로 직접 연결
    • 인그레스 컨트롤러 파드는 K8S API서버로부터 서비스의 엔드포인트 정보(파드 IP)를 획득 후 바로 파드의 IP로 연결 - 링크
    • 지원되는 인그레스 컨트롤러 : Nginx, Traefix 등 현재 대부분의 인그레스 컨트롤러가 지원함.

 

Nginx 인그레스 컨트롤러 설치

 

인그레스 컨트롤러 : 인그레스의 실제 동작 구현은 인그레스 컨트롤러(Nginx, Kong 등)가 처리 - 링크

  • 쿠버네티스는 Ingress API 만 정의하고 실제 구현은 add-on 에 맡김
  • Ingress-Nginx Controller - 링크 ⇒ 간편한 테스트를 위해서 NodePort 타입(externalTrafficPolicy: Local) 설정

그림 출처 https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/baremetal.md

 

  • 다양한 Nginx 인그레스 컨트롤러 인입 방법
    • MetalLB 사용, Via the host network 사용, Using a self-provisioned edge 사용, External IPs 사용 - 링크
  • Ingress NGINX Controller for Kubernetes - Home , Github
  • Ingress-Nginx 컨트롤러 생성 - ArtifactHub release
    # Ingress-Nginx 컨트롤러 생성
    cat <<EOT> ingress-nginx-values.yaml
    controller:
      service:
        type: NodePort
        nodePorts:
          http: 30080
          https: 30443
      nodeSelector:
        kubernetes.io/hostname: "k3s-s"
      metrics:
        enabled: true
      serviceMonitor:
          enabled: true
    EOT
    
    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update
    
    kubectl create ns ingress
    helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2
    
    # 확인
    kubectl get all -n ingress
    kc describe svc -n ingress ingress-nginx-controller
    
    # externalTrafficPolicy 설정
    kubectl patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'
    
    # 기본 nginx conf 파일 확인
    kc describe cm -n ingress ingress-nginx-controller
    kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
    
    # 관련된 정보 확인 : 포드(Nginx 서버), 서비스, 디플로이먼트, 리플리카셋, 컨피그맵, 롤, 클러스터롤, 서비스 어카운트 등
    kubectl get all,sa,cm,secret,roles -n ingress
    kc describe clusterroles ingress-nginx
    kubectl get pod,svc,ep -n ingress -o wide -l app.kubernetes.io/component=controller
    
    # 버전 정보 확인
    POD_NAMESPACE=ingress
    POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o name)
    kubectl exec $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
      

 

  • (옵션) kubectl krew 설치 - 링크 & ingress-nginx plugin 설치 - 링크
    # (참고) 운영체제 확인 : linux
    OS="$(uname | tr '[:upper:]' '[:lower:]')"
    # (참고)  CPU 아키텍처 확인 : amd64
    ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
    # (참고)  KREW 지정 : krew-linux_amd64
    KREW="krew-${OS}_${ARCH}"
    
    # kubectl krew 설치
    # curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz"
    curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz" && tar zxvf krew-linux_amd64.tar.gz && ./krew-linux_amd64 install krew
    export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
    
    # 플러그인 정보 업데이트 후 확인 - 링크
    kubectl krew update
    kubectl krew search
    
    # ingress-nginx 플러그인 설치
    kubectl krew install ingress-nginx
    
    # ingress-nginx 플러그인 명령어 실행(도움말 출력)
    kubectl ingress-nginx
    
    # nginx ctrl 의 backends 설정 정보 출력
    kubectl ingress-nginx backends -n ingress-nginx --list
    kubectl ingress-nginx backends -n ingress-nginx
    
    # conf 출력
    kubectl ingress-nginx conf -n ingress-nginx
    ## 특정 호스트(도메인) 설정 확인
    kubectl ingress-nginx conf -n ingress-nginx --host gasida.cndk.link
    kubectl ingress-nginx conf -n ingress-nginx --host nasida.cndk.link
    
    # 정보 보기 편함!
    kubectl ingress-nginx ingresses
    kubectl ingress-nginx ingresses --all-namespaces

 

인그레스(Ingress) 실습 및 통신 흐름 확인

 

[ 실습 구성도 ]

  • 컨트롤플레인 노드에 인그레스 컨트롤러(Nginx) 파드를 생성, NodePort 로 외부에 노출
  • 인그레스 정책 설정 : Host/Path routing, 실습의 편리를 위해서 도메인 없이 IP로 접속 설정 가능
    https://kschoi728.tistory.com/266 스터디 실습 기본 환경 참고

[ 디플로이먼트와 서비스를 생성 ]

  • svc1-pod.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deploy1-websrv
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: websrv
      template:
        metadata:
          labels:
            app: websrv
        spec:
          containers:
          - name: pod-web
            image: nginx
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: svc1-web
    spec:
      ports:
        - name: web-port
          port: 9001
          targetPort: 80
      selector:
        app: websrv
      type: ClusterIP
  • svc2-pod.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deploy2-guestsrv
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: guestsrv
      template:
        metadata:
          labels:
            app: guestsrv
        spec:
          containers:
          - name: pod-guest
            image: gcr.io/google-samples/kubernetes-bootcamp:v1
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: svc2-guest
    spec:
      ports:
        - name: guest-port
          port: 9002
          targetPort: 8080
      selector:
        app: guestsrv
      type: NodePort
  • svc3-pod.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deploy3-adminsrv
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: adminsrv
      template:
        metadata:
          labels:
            app: adminsrv
        spec:
          containers:
          - name: pod-admin
            image: k8s.gcr.io/echoserver:1.5
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: svc3-admin
    spec:
      ports:
        - name: admin-port
          port: 9003
          targetPort: 8080
      selector:
        app: adminsrv
  • 생성 및 확인
    # 모니터링
    watch -d 'kubectl get ingress,svc,ep,pod -owide'
    
    # 생성
    kubectl taint nodes k3s-s role=controlplane:NoSchedule
    curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc1-pod.yaml
    curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc2-pod.yaml
    curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc3-pod.yaml
    kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml
    
    # 확인 : svc1, svc3 은 ClusterIP 로 클러스터 외부에서는 접속할 수 없다 >> Ingress 는 연결 가능!
    kubectl get pod,svc,ep

Ingress Nginx가 Backend pod ip로 바로 접근 가능해 Type: ClusterIP/NodePort 상관 없다

 

 

[ 인그레스(정책) 생성 - 링크 ]

  • ingress1.yaml
    https://kschoi728.tistory.com/266
    cat <<EOT> ingress1.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-1
      annotations:
        #nginx.ingress.kubernetes.io/upstream-hash-by: "true"
    spec:
      ingressClassName: nginx
      rules:
      - http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: svc1-web
                port:
                  number: 80
          - path: /guest
            pathType: Prefix
            backend:
              service:
                name: svc2-guest
                port:
                  number: 8080
          - path: /admin
            pathType: Prefix
            backend:
              service:
                name: svc3-admin
                port:
                  number: 8080
    EOT
  • 인그레스 생성 및 확인
    # 모니터링
    watch -d 'kubectl get ingress,svc,ep,pod -owide'
    
    # 생성
    kubectl apply -f ingress1.yaml
    
    # 확인
    kubectl get ingress
    kc describe ingress ingress-1
    ...
    Rules:
      Host        Path  Backends
      ----        ----  --------
      *           
                  /        svc1-web:80 ()
                  /guest   svc2-guest:8080 ()
                  /admin   svc3-admin:8080 ()
    ...
    
    # 설정이 반영된 nginx conf 파일 확인
    kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
    kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf | grep 'location /' -A5
    		location /guest/ {
    
    			set $namespace      "default";
    			set $ingress_name   "ingress-1";
    			set $service_name   "svc2-guest";
    			set $service_port   "8080";
    --
      		location /admin/ {
    
    			set $namespace      "default";
    			set $ingress_name   "ingress-1";
    			set $service_name   "svc3-admin";
    			set $service_port   "8080";
    --
      		location / {
    
    			set $namespace      "default";
    			set $ingress_name   "ingress-1";
    			set $service_name   "svc1-web";
    			set $service_port   "80";
    --
    ...

    • rule: 
      *  : 어떤 서비스든 OK. prefix 경로에 따라 뒤에 label selecting 된 pod로 traffic 분기 

 

 

 

[ 인그레스를 통한 내부 접속 ]

  • Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로 : 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결 (아래 오른쪽 그림)
    1. 인그레스 접속 경로 : Ingress → 애플리케이션 서비스(Service) → 애플리케이션(Deploy, Pod 등) 2.  인그레스 접속 경로(서비스 Bypass) : Ingress → 애플리케이션(Deploy, Pod 등)
  • 인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인*** : HTTP 부하분산 & PATH 기반 라우팅, 애플리케이션 파드에 연결된 서비스는 Bypass