home..

Ingress에 대하여

mont-kim Docker Container Pod Container Kubernetes Service

About Ingress

인그레스(Ingress) 를 통한 통신 흐름

Nginx 인그레스 컨트롤러 경우 : 외부에서 인그레스로 접속 시 Nginx 인그레스 컨트롤러 파드로 인입되고, 이후 애플리케이션 파드의 IP로 직접 통신

클러스터 내부를 외부에 노출 - 발전 단계

Untitled.png

클러스터 내부를 외부에 노출 - 발전 단계

👉🏻 인그레스의 주요 동작에 대한 내용은 생략하였고, 인그레스를 통한 통신 흐름에 집중하여 설명을 하였음을 미리 알려드립니다 🙂

  1. 파드 생성 : K8S 클러스터 내부에서만 접속

    Untitled1.png

  2. 서비스(Cluster Type) 연결 : K8S 클러스터 내부에서만 접속
    • 동일한 애플리케이션의 다수의 파드의 접속을 용이하게 하기 위한 서비스에 접속

    Untitled2.png

  3. 서비스(NodePort Type) 연결 : 외부 클라이언트가 서비스를 통해서 클러스터 내부의 파드로 접속
    • 서비스(NodePort Type)의 일부 단점을 보완한 서비스(LoadBalancer Type) 도 있습니다!

    Untitled3.png

  4. 인그레스 컨트롤러 파드를 배치 : 서비스 앞단에 HTTP 고급 라우팅 등 기능 동작을 위한 배치
    • 인그레스(정책)이 적용된 인그레스 컨트롤러 파드(예. nginx pod)를 앞단에 배치하여 고급 라우팅 등 기능을 제공

    Untitled4.png

  5. 인그레스 컨트롤러 파드 이중화 구성 : Active(Leader) - Standby(Follower) 로 Active 파드 장애에 대비

    Untitled5.png

  6. 인그레스 컨트롤러 파드외부에 노출 : 인그레스 컨트롤러 파드를 외부에서 접속하기 위해서 노출(expose)
    • 인그레스 컨트롤러 노출 시 서비스(NodePort Type) 보다는 좀 더 많은 기능을 제공하는 서비스(LoadBalancer Type)를 권장합니다 (80/443 포트 오픈 시)

    Untitled6.png

  7. 인그레스와 파드간 내부 연결의 효율화 방안 : 인그레스 컨트롤러 파드(Layer7 동작)에서 서비스 파드의 IP로 직접 연결
    • 인그레스 컨트롤러 파드는 K8S API서버로부터 서비스의 엔드포인트 정보(파드 IP)를 획득 후 바로 파드의 IP로 연결 - 링크
    • 지원되는 인그레스 컨트롤러 : Nginx, Traefix 등 현재 대부분의 인그레스 컨트롤러가 지원함

    Untitled.png

image.png

image.png

Ingress란?

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

  • Make your HTTP (or HTTPS) network service available using a protocol-aware configuration mechanism, that understands web concepts like URIs, hostnames, paths, and more. The Ingress concept lets you map traffic to different backends based on rules you define via the Kubernetes API.
  • An API object that manages external access to the services in a cluster, typically HTTP.
  • Ingress may provide load balancingSSL termination and namebased virtual hosting.
  • Ingress is frozen. New features are being added to the Gateway API.
  • 그림 소개 : 출처 - 김태민 기술 블로그 - 링크
    • 인그레스 기능 : HTTP(서비스) 부하분산 , 카나리 업그레이드
    • 인그레스 컨트롤러 : 인그레스의 실제 동작 구현은 인그레스 컨트롤러(Nginx, Kong 등)가 담당
    • 인그레스 + 인그레스 컨트롤러(Nginx) 기능 : HTTP(서비스) 부하분산 , 카나리 업그레이드 , HTTPS 처리(TLS 종료)
  • Ingress 비교 - 링크

Ingress Controller 설치

Ingress Controller는 인입되는 요청을 적절한 서비스로 전달해주는 역할입니다. 하지만, 이 Ingress Controller 조차 클러스터 내부로의 트래픽 인입을 위한 “외부노출”이 되어야 도메인 기반의 라우팅이 가능해집니다.

인그레스(Ingress) 소개 : 클러스터 내부의 HTTP/HTTPS 서비스를 외부로 노출(expose) - 링크

[https://www.tkng.io/ingress/ingress/](https://www.tkng.io/ingress/ingress/)

https://www.tkng.io/ingress/ingress/

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

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

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

    그림 출처 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 is an Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer.
    • How it works : configmap 설정을 nginx config 에 적용(by lua), 변경 시 (최소) reload - Docs
      • The goal of this Ingress controller is the assembly of a configuration file (nginx.conf).
      • The main implication of this requirement is the need to reload NGINX after any change in the configuration file.
        • Though it is important to note that we don’t reload Nginx on changes that impact only an upstream configuration (i.e Endpoints change when you deploy your app).
      • We use lua-nginx-module to achieve this. Check below to learn more about how it’s done.
      • When a reload is required
        • New Ingress Resource Created.
        • TLS section is added to existing Ingress.
        • Change in Ingress annotations that impacts more than just upstream configuration. For instance load-balance annotation does not require a reload.
        • A path is added/removed from an Ingress.
        • An Ingress, Service, Secret is removed.
        • Some missing referenced object from the Ingress is available, like a Service or Secret.
        • A Secret is updated.

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
  • [도전과제1] Ingress-Nginx Controller 를 host network 로 설치 및 실습 후 동작 정리 - Docs

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

실습 구성도

  • 컨트롤플레인 노드에 인그레스 컨트롤러(Nginx) 파드를 생성, NodePort 로 외부에 노출
  • 인그레스 정책 설정 : Host/Path routing, 실습의 편리를 위해서 도메인 없이 IP로 접속 설정 가능

Untitled

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

  • 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 Routing Rule 생성

링크

  • ingress1.yaml

      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
        
    
  • 인그레스 생성 및 확인

      # 생성
      kubectl apply -f ingress1.yaml
        
      # 확인
      kubectl get ingress
        
      # 설정이 반영된 nginx conf 파일 확인
      kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf | grep 'location /' -A5
        
      ...
        
    

인그레스를 통한 내부 접속

  • Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로 : 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결 (아래 오른쪽 그림)

인그레스 접속 경로 : Ingress → 애플리케이션 서비스(Service) → 애플리케이션(Deploy, Pod 등)

인그레스 접속 경로 : Ingress → 애플리케이션 서비스(Service) → 애플리케이션(Deploy, Pod 등)

인그레스 접속 경로(서비스 Bypass) : Ingress → 애플리케이션(Deploy, Pod 등)

인그레스 접속 경로(서비스 Bypass) : Ingress → 애플리케이션(Deploy, Pod 등)

  • (참고) URI(Uniform Resource Identifier, RFC3986)
    • Request URI 는 서버 주소나 파일 이름, 파라미터 등 다양한 리소스를 식별하기 위해 사용하는 문자열입니다.
    • 절대 URI(absolute URI, 필요한 모든 정보를 기술) 와 상대 URI(relative URI, 상대적인 위치)가 있습니다.
      • 스킴이름 // 서버 주소 : 포트 번호 / 파일 경로 ? 쿼리 문자열 # 프래그먼트 식별자

      책 '그림으로 공부하는 TCP/IP 구조' 중 발췌

      책 ‘그림으로 공부하는 TCP/IP 구조’ 중 발췌

  • (참고) X-Forwarded-For 헤더, X-Forwarded-Proto 헤더
    • X-Forwarded-For 헤더는 송신지 IP 주소가 변환되는 환경(장비, 서버, 솔루션 등)에서, 변환 전 송신지(클라이언트) IP 주소를 저장하는 헤더입니다.
    • X-Forwarded-Proto 헤더는 변환 전 프로토콜을 저장합니다. (예. SSL Offload 환경에서 서버 측에서 클라이언트가 요청 시 사용한 원래 프로토콜을 확인)

    Untitled12.png

    • Client IP 를 가져오는 방법
      • 웹 애플리케이션이 client IP를 추출하기 위해서 Http request header를 다음과 같은 순서로 뒤짐
        1. Proxy-Client-IP : 특정 웹 어플리케이션에서 사용 (예. WebLogic Connector - mod_wl)
        2. WL-Proxy-Client-IP : 특정 웹 어플리케이션에서 사용 (예. WebLogic Connector - mod_wl)
        3. X-Forwarded-For : HTTP RFC 표준에는 없지만 사실상 표준!!!
        4. request.getRemoteAddr()
        5. CLIENT_IP
      • 3번 X-Forwarded-For: , , 요청이 여러 프록시를 거치는 경우 X-Forwarded-For 요청 헤더의 clientIPAddress 다음에는 로드 밸런서에 도달하기 전에 요청이 통과하는 각 연속 프록시의 IP주소가 온다. 따라서, 가장 오른쪽의 IP 주소는 가장 최근의 프록시의 IP주소이고 가장 왼쪽의 IP 주소는 원래 클라이언트의 IP 주소이다.
      • 참고 링크 : 링크1 링크2
    • (참고) nginx ingress controller 기본 설정 : forwarded-for-header - 링크
    [“진짜” 클라이언트 IP의 위험성 GeekNews](https://news.hada.io/topic?id=6098)
  • 인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인 : HTTP 부하분산 & PATH 기반 라우팅, 애플리케이션 파드에 연결된 서비스는 Bypass

      # (krew 플러그인 설치 시) 인그레스 정책 확인
      ~~kubectl ingress-nginx ingresses~~
      INGRESS NAME   HOST+PATH   ADDRESSES       TLS   SERVICE      SERVICE PORT   ENDPOINTS
      ingress-1      /           192.168.10.10   NO    svc1-web     80             1
      ingress-1      /guest      192.168.10.10   NO    svc2-guest   8080           2
      ingress-1      /admin      192.168.10.10   NO    svc3-admin   8080           3
        
      #
      kubectl get ingress
      NAME        CLASS   HOSTS   ADDRESS        PORTS   AGE
      ingress-1   nginx   *       10.10.200.24   80      3m44s
         
      kubectl describe ingress ingress-1 | sed -n "5, \$p"
      Rules:
        Host        Path   Backends
        ----        ----   --------
        *           /      svc1-web:80 ()
                    /guest svc2-guest:8080 ()
                    /admin svc3-admin:8080 ()
        
      # 접속 로그 확인 : kubetail 설치되어 있음 - 출력되는 nginx 의 로그의 IP 확인
      kubetail -n ingress -l app.kubernetes.io/component=controller
        
      -------------------------------
      # 자신의 집 PC에서 인그레스를 통한 접속 : 각각
      echo -e "Ingress1 sv1-web URL = http://$(curl -s ipinfo.io/ip):30080"
      echo -e "Ingress1 sv2-guest URL = http://$(curl -s ipinfo.io/ip):30080/guest"
      echo -e "Ingress1 sv3-admin URL = http://$(curl -s ipinfo.io/ip):30080/admin"
        
      # svc1-web 접속
      MYIP=<EC2 공인 IP>
      MYIP=13.124.93.150
      curl -s $MYIP:30080
        
      # svvc2-guest 접속
      curl -s $MYIP:30080/guest
      curl -s $MYIP:30080/guest
      for i in {1..100}; do curl -s $MYIP:30080/guest ; done | sort | uniq -c | sort -nr
        
      # svc3-admin 접속 > 기본적으로 Nginx 는 라운드로빈 부하분산 알고리즘을 사용 >> Client_address 와 XFF 주소는 어떤 주소인가요?
      curl -s $MYIP:30080/admin
      curl -s $MYIP:30080/admin | egrep '(client_address|x-forwarded-for)'
      for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
        
      # (옵션) 디플로이먼트의 파드 갯수를 증가/감소 설정 후 접속 테스트 해보자
    
    • 노드에서 아래 패킷 캡처 확인 : flannel vxlan, 파드 간 통신 시 IP 정보 확인
      #
      ngrep -tW byline -d ens5 '' udp port 8472 or tcp port 80
        
      #
      tcpdump -i ens5 udp port 8472 -nn
        
      # vethY는 각자 k3s-s 의 가장 마지막 veth 를 지정
      tcpdump -i vethY tcp port 8080 -nn
      tcpdump -i vethY tcp port 8080 -w /tmp/ingress-nginx.pcap
        
      # 자신의 PC에서 k3s-s EC2 공인 IP로 pcap 다운로드
      scp ubuntu@<k3s-s EC2 공인 IP>:/tmp/ingress-nginx.pcap ~/Downloads
    

    CleanShot 2024-10-06 at 21.07.55.png

    • Nginx 파드가 endpoint 정보 등을 모니터링 가능한 이유 : 클러스터롤과 롤(엔드포인트 list, watch)를 바인딩된 서비스 어카운트를 파드가 사용!
      kubectl describe clusterrole ingress -n ingress | egrep '(Verbs|endpoints)'
      [root@k8s-m:~/yaml (ctx-k8s:default)]# kubectl describe clusterrole ingress-nginx -n ingress-nginx | egrep '(Verbs|endpoints)'
        Resources                           Non-Resource URLs  Resource Names  Verbs
        endpoints                           []                 []              [list watch]
        
      kubectl describe roles ingress-nginx -n ingress | egrep '(Verbs|endpoints)'
      [root@k8s-m:~/yaml (ctx-k8s:default)]# kubectl describe roles ingress-nginx -n ingress-nginx | egrep '(Verbs|endpoints)'
        Resources                           Non-Resource URLs  Resource Names                     Verbs
        endpoints                           []                 []                                 [get list watch]
    
    • (심화) nginx ingress controller 이 endpoint ip(port) list 획득 코드 내용 - 링크
      klog.V(3).Infof("Getting Endpoints for Service %q and port %v", svcKey, port.String())
      	ep, err := getServiceEndpoints(svcKey)
      	if err != nil {
      		klog.Warningf("Error obtaining Endpoints for Service %q: %v", svcKey, err)
      		return upsServers
      	}
    
  • 외부 클라이언트(192.168.100.1) → 인그레스 접속 시(192.168.100.10:Port) : 각기 path 에 따른 연결

    43.png

    파드외부 클라이언트의 IP 획득을 위해서 X-Forwarded-For(XFF)를 참조를 해야 합니다!

  • (심화 참고) nginx-ingress 설정 시 annotation으로 설정 불가능한 것을 적용 시 ConfigMap 으로 설정 - 링크

패킷 분석

  • 외부에서 접속(그림 왼쪽) 후 Nginx 파드(Layer7 동작)는 HTTP 헤더에 정보 추가(XFF)후 파드의 IP로 직접 전달

    wireshark 필터 : http.x_forwarded_for

    wireshark 필터 : http.x_forwarded_for

    Wireshark Custom Column 추가(XFF)

    Wireshark Custom Column 추가(XFF)

    ingress1-ok.pcap

  • (옵션) 패킷 분석 » 파드(veth) 패킷 캡쳐 후 merge 하였습니다 : Proxy(대리인) 존재감 확인!

    • 중간 빨간색 부분이 Nginx 파드의 IP(172.16.29.11)입니다 → 외부에서 Nginx 파드에 접속 후 Nginx 파드가 내부의 파드 IP로 직접 연결(옵션:부하분산)

    8.17.15.png

    ingress1-ok.pcap

      # 아래 ENDPOINTS 출력된 지점으로 요청이 바로 전달됩니다.
      kubectl get ep | grep -v kubernetes
      NAME         ENDPOINTS                                                AGE
      svc1-web     172.16.228.72:80                                         14h
      svc2-guest   172.16.197.8:8080,172.16.46.7:8080                       14h
      svc3-admin   172.16.228.78:8080,172.16.46.13:8080,172.16.46.14:8080   14h                        
    

패킷 분석

  • 외부에서 접속(그림 왼쪽) 후 Nginx 파드(Layer7 동작)는 HTTP 헤더에 정보 추가(XFF)후 파드의 IP로 직접 전달

    wireshark 필터 : http.x_forwarded_for

    Wireshark Custom Column 추가(XFF) ingress1-ok.pcap

  • (옵션) 패킷 분석 » 파드(veth) 패킷 캡쳐 후 merge 하였습니다 : Proxy(대리인) 존재감 확인!

    • 중간 빨간색 부분이 Nginx 파드의 IP(172.16.29.11)입니다 → 외부에서 Nginx 파드에 접속 후 Nginx 파드가 내부의 파드 IP로 직접 연결(옵션:부하분산)

    ingress1-ok.pcap

      # 아래 ENDPOINTS 출력된 지점으로 요청이 바로 전달됩니다.
      kubectl get ep | grep -v kubernetes
      <사진>
        
    

Nginx 분산 알고리즘 변경

  • nginx 는 기본 RR 라운드 로빈 이지만, IP-Hash 나 Session Cookie 설정으로 대상 유지 가능 - 링크
# mypc
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

# 아래 ingress 설정 중 IP-Hash 설정 > # 주석 제거
sed -i 's/#nginx.ingress/nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml

# 접속 확인
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

# 다시 원복(라운드 로빈) > # 주석 추가
sed -i 's/nginx.ingress/#nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml

# 접속 확인
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

  • 오브젝트 삭제
kubectl delete deployments,svc,ingress --all

AWS Ingress (ALB) 모드

  • 인스턴스 모드 : AWS ALB(Ingress)로 인입 후 각 워커노드의 NodePort 로 전달 후 IPtables 룰(SEP)에 따라 파드로 분배

Untitled

  • IP 모드 : nginx ingress controller 동작과 유사하게 AWS LoadBalancer Controller 파드가 kube api 를 통해서 파드의 IP를 제공받아서 AWS ALB 에 타켓(파드 IP)를 설정

Untitled

3.6 Host 기반 라우팅

  • ingress2.yaml

      cat <<EOT> ingress2.yaml
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: ingress-2
      spec:
        ingressClassName: nginx
        rules:
        - host: kans.com
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: svc3-admin
                  port:
                    number: 8080
        - host: "*.kans.com"
          http:
            paths:
            - path: /echo
              pathType: Prefix
              backend:
                service:
                  name: svc3-admin
                  port:
                    number: 8080
      EOT
        
    
  • 인그레스 생성 및 확인

    👉🏻 kans.com 도메인은 각자 자신의 닉네임으로 변경합니다!

    # 생성 
    curl -s -O <https://raw.githubusercontent.com/gasida/DKOS/main/6/k> sed -i 's/dkos.com/<각자 자신의 닉네임의 도메인>/g' k3s-ingress2.yaml 
    kubectl apply -f k3s-ingress2.yaml 
    kubectl get ingress kubectl describe ingress ingress-2
    
  • 인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인

      # 로그 모니터링
      kubetail -n ingress -l app.kubernetes.io/component=controller
        
      # (옵션) ingress nginx 파드 vethY 에서 패킷 캡처 후 확인 해 볼 것
        
      ------------
      # 자신의 PC 에서 접속 테스트
      # svc3-admin 접속 > 결과 확인 : 왜 접속이 되지 않는가? HTTP 헤더에 Host 필드를 잘 확인해보자!
      curl $MYIP:30080 -v
      curl $MYIP:30080/echo -v
        
      # mypc에서 접속을 위한 설정
      ## /etc/hosts 수정 : 도메인 이름으로 접속하기 위해서 변수 지정
      ## 맥 sudo vim /etc/hosts
      MYDOMAIN1=montkim.org
      MYDOMAIN2=test.montkim.org
      echo $MYIP $MYDOMAIN1 $MYDOMAIN2
        
      echo "$MYIP $MYDOMAIN1" | sudo tee -a /etc/hosts
      echo "$MYIP $MYDOMAIN2" | sudo tee -a /etc/hosts
      cat /etc/hosts | grep $MYDOMAIN1
        
      ~~~~# svc3-admin 접속 > 결과 확인
      curl $MYDOMAIN1:30080 -v
      curl $MYDOMAIN1:30080/admin
      curl $MYDOMAIN1:30080/echo
      curl $MYDOMAIN1:30080/echo/1
        
      curl $MYDOMAIN2:30080 -v
      curl $MYDOMAIN2:30080/admin
      curl $MYDOMAIN2:30080/echo
      curl $MYDOMAIN2:30080/echo/1
      curl $MYDOMAIN2:30080/echo/1/2
        
      ## (옵션) /etc/hosts 파일 변경 없이 접속 방안
      curl -H "host: $MYDOMAIN1" $MYIP:30080
        
    
  • 오브젝트 삭제

kubectl delete deployments,svc,ingress --all

3.7 카나리 업그레이드

  • 배포 자동화 지원(최소 중단, 무중단) - 롤링 업데이트, 카나리 업데이트, 블루/그린 업데이트 - 링크 링크2 하이커퍼넥스-블로그
    • 롤링 업데이트
    • 카나리 업데이트
    • 블루/그린 업데이트

https://kubernetes.github.io/ingress-nginx/examples/canary/

업그레이드 전략은 각 배포하는 툴에 따라서 다른 방법들을 선택할수도 있지만, 이번에는 ingress nginx 측에서 제공되는 ingress로 라우팅을 통한 Canary 배포를 진행해봅니다.

  • Canary in the coal mine

    [https://share.america.gov/english-idiom-canary-coal-mine/](https://share.america.gov/english-idiom-canary-coal-mine/)

    https://share.america.gov/english-idiom-canary-coal-mine/

    Untitled

  • canary-ingress1.yaml

      cat <<EOT> canary-ingress1.yaml
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: ingress-canary-v1
      spec:
        ingressClassName: nginx
        rules:
        - host: kans.com
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: svc-v1
                  port:
                    number: 8080
      EOT
        
    
  • canary-ingress2.yaml

      cat <<EOT> canary-ingress2.yaml
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: ingress-canary-v2
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"
          nginx.ingress.kubernetes.io/canary-weight: "10"
      spec:
        ingressClassName: nginx
        rules:
        - host: kans.com
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: svc-v2
                  port:
                    number: 8080
      EOT
        
    
  • 카나리 업그레이드 확인

      # 터미널1
      watch -d 'kubectl get ingress,svc,ep'
        
      # 도메인 변경
      MYDOMAIN1=montkim.org
      sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress1.yaml
      sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress2.yaml
        
      # 생성
      kubectl apply -f canary-ingress1.yaml,canary-ingress2.yaml
        
      # 로그 모니터링
      kubetail -n ingress -l app.kubernetes.io/component=controller
        
      # 접속 테스트
      curl -s $MYDOMAIN1:30080
      curl -s $MYDOMAIN1:30080 | grep nginx
        
      # 접속 시 v1 v2 버전별 비율이 어떻게 되나요? 왜 이렇게 되나요?
      for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
        
      # 비율 조정 >> 개발 배포 버전 전략에 유용하다!
      kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=50
        
      # 접속 테스트
      for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
      for i in {1..1000}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
        
      # (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
      kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=100
      for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
        
      # (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
      kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=0
      for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
        
    
  • 오브젝트 삭제 kubectl delete deployments,svc,ingress --all

HTTPS 처리(TLS 종료)

Cert Manager

Cert Manager는 Kubernetes에서 자동화된 SSL/TLS 인증서 관리를 제공하는 addon 입니다. Cert Manager는 Let’s Encrypt와 같은 인증 기관(ACME)으로부터 인증서를 자동으로 발급하고, 갱신하는 기능을 제공합니다.

  1. 자동 인증서 발급: Cert Manager는 Kubernetes의 CertificateRequest 리소스를 사용하여 인증서를 자동으로 발급할 수 있습니다. 이를 통해 사용자는 수동으로 인증서를 발급하거나 갱신할 필요가 없습니다.
  2. 인증서 갱신: Cert Manager는 인증서의 유효 기간이 만료되기 전에 자동으로 인증서를 갱신합니다. 이는 인증서 만료로 인한 서비스 중단을 방지합니다.
  3. Ingress 통합: Cert Manager는 Kubernetes의 Ingress 리소스와 통합되어, 애플리케이션에 SSL/TLS 인증서를 쉽게 제공할 수 있습니다. Ingress 리소스에 어노테이션을 추가하면, Cert Manager는 해당 서비스에 대한 인증서를 자동으로 발급하고, Ingress 리소스를 업데이트하여 트래픽이 해당 인증서를 사용하도록 합니다.
  4. Certificate 표준 리소스 사용: Cert Manager는 쿠버네티스의 Certificate, CertificateRequest, Issuer, ClusterIssuer 등의 리소스를 사용하여 인증서를 관리합니다. 이를 통해 쿠버네티스 API를 사용하여 인증서의 Lifecycle을 관리할 수 있습니다.

Cert Manager는 Kubernetes에서 SSL/TLS 인증서 관리를 단순화하고, 자동화하므로, 사용자는 보안에 대한 걱정 없이 애플리케이션에 집중할 수 있습니다.

그러면 빠르고 간단하게 Cert Manger설치하는 방법을 다루고 다음단계로 넘어가겠습니다.

helm repo add cert-manager https://charts.jetstack.io
helm repo update
helm upgrade --install my-cert-manager cert-manager/cert-manager --version 1.12.2 -n cert-manager --create-namespace --set installCRDs=true

cert manager 공식 helm repo에서 받아온 이미지로 설치를 진행합니다.

별도로 value 파일을 작성할 필요없이 파라미터로 install CRD만 활성화 했기때문에 저 명령어대로 설치를 진행합니다.

Cluster Issuer

Cert Manager를 사용하려면, Issuer 또는 ClusterIssuer를 생성해야 합니다. Cert Manager가 인증서를 발급하기 위해 사용하는 구성 요소 입니다. ClusterIssuer는 클러스터 전체의 모든 네임스페이스에서 인증서를 발급할 수 있습니다.

예를 들어, Let’s Encrypt를 사용하는 ClusterIssuer를 생성하려면 다음과 같은 YAML 파일(cluster-issuer.yaml)을 만들어 kubectl로 적용합니다:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

위와같이 cluster issuer를 발급하고나면, ingress 를 생성할 때 annotation에 cluster-issuer를 적어줌으로서 발급하고자 하는 ingress에 대한 https let’s encrypt 인증서를 발급 받을 수 있습니다.

HTTPS 처리

  • svc-pod.yaml

      apiVersion: v1
      kind: Pod
      metadata:
        name: pod-https
        labels:
          app: https
      spec:
        containers:
        - name: container
          image: k8s.gcr.io/echoserver:1.6
        terminationGracePeriodSeconds: 0
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: svc-https
      spec:
        selector:
          app: https
        ports:
        - port: 8080
        
    
  • ssl-termination-ingress.yaml

      cat <<EOT> ssl-termination-ingress.yaml
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: https
      spec:
        ingressClassName: nginx
        tls:
        - hosts:
          - kans.com
          secretName: secret-https
        rules:
        - host: kans.com
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: svc-https
                  port:
                    number: 8080
      EOT
        
    
  • 생성 확인 및 secret 생성 후 접속 확인

      # 서비스와 파드 생성
      curl -s -O <https://raw.githubusercontent.com/gasida/NDKS/main/7/svc-pod.yaml>
      kubectl apply -f svc-pod.yaml
        
      # 도메인 변경
      MYDOMAIN1=montkim.org
      echo $MYDOMAIN1
      sed -i "s/montkim.org/$MYDOMAIN1/g" ssl-termination-ingress.yaml
        
      # 인그레스 생성
      kubectl apply -f ssl-termination-ingress.yaml
        
      # 인증서 생성
      # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=dkos.com/O=dkos.com"mkdir key && cd key
      MYDOMAIN1=montkim.org
      openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
      tree
        
      # Secret 생성
      kubectl create secret tls secret-https --key tls.key --cert tls.crt
        
      # Secret 확인
      kubectl get secrets secret-https
      kubectl get secrets secret-https -o yaml
        
      -------------------
      # 자신의 PC 에서 접속 확인 : PC 웹브라우저
        
    

위에서 설명한 Cluster Issuer와 Cert Manger를 이용한 인증서 자동발급도 가능합니다.

다만 내가 클러스터가 연결 가능한 Public IP로 도메인의 80/443 포트랑 맵핑 후, 인증서를 발급받아 Secret으로 생성해주는 역할을 합니다.

제 블로그의 Ingress 파일이고,cert-manager에서 생성한 cluster-issuer로 인증서를 발급합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jekyll-ingress-new
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  rules:
    - host: montkim.com
      http:
        paths:
          - pathType: Prefix
            path: "/"
            backend:
              service:
                name: jekyll-service
                port:
                  number: 80
  tls:
    - hosts:
        - montkim.com
      secretName: jekyll-tls

image.png

# 서비스와 파드 생성
curl -s -O <https://raw.githubusercontent.com/gasida/NDKS/main/7/svc-pod.yaml>
kubectl apply -f svc-pod.yaml

# 도메인 변경
MYDOMAIN1=montkim.org
echo $MYDOMAIN1
sed -i "s/montkim.org/$MYDOMAIN1/g" ssl-termination-ingress.yaml

# 인그레스 생성
kubectl apply -f ssl-termination-ingress.yaml

# 인증서 생성
# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=dkos.com/O=dkos.com"mkdir key && cd key
MYDOMAIN1=montkim.org
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
tree

# Secret 생성
kubectl create secret tls secret-https --key tls.key --cert tls.crt

# Secret 확인
kubectl get secrets secret-https
kubectl get secrets secret-https -o yaml

-------------------
# 자신의 PC 에서 접속 확인 : PC 웹브라우저

  • Nginx SSL Termination 패킷 확인 : 중간 172.16.29.11 이 nginx controller

      # 패킷 캡처 명령어 참고
      export IngHttp=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
      export IngHttps=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[1].nodePort}')
      tcpdump -i <nginx 파드 veth> -nnq tcp port 80 or tcp port 443 or tcp port 8080 or tcp port $IngHttp or tcp port $IngHttps
      tcpdump -i <nginx 파드 veth> -nn  tcp port 80 or tcp port 443 or tcp port 8080 or tcp port $IngHttp or tcp port $IngHttps -w /tmp/ingress.pcap
    

    wireshark 필터 tls.record.opaque_type == 23 or http

    wireshark 필터 tls.record.opaque_type == 23 or http

    ingress-tls.pcap

    Untitled

  • 오브젝트 삭제 kubectl delete pod,svc,ingress --all
  • Nginx 인그레스 컨트롤러 삭제 helm uninstall -n ingress ingress-nginx
  • Chrome 에서 사설인증서 제공 https 사이트 접속 시 thisisunsafe 입력 - 링크

3.9 (옵션) HTTP → HTTPS Redirect 설정

HTTPS Redirect 설정하기

ingress 로 맵핑된 도메인을 강제로 redirect 설정이 가능합니다.

링크

설정 및 확인

# nginx 서비스 편집 : 아래 내용 추가
kubectl edit svc -n ingress-nginx ingress-nginx-controller
---
  annotaion
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
---

http(kans.com) 접속 시 308 Redirect 로 https(kans.com)으로 접속된다

http(kans.com) 접속 시 308 Redirect 로 https(kans.com)으로 접속된다

  • 참고 308 Permanent Redirect - 링크

Custom Error Page 튜닝하기

링크

고객사에서 웹서비스를 ingress nginx 로 사용하면서, 커스텀 에러페이지를 설정한 적이 있습니다.

nginx 자체를 사용하기 편하게 해둔것으로, 애드온 설정들처럼 ingress nginx 배포시에 같이 배포하면 Error 페이지또한 튜닝이 가능합니다.

설정 및 확인

# 404, 503, 500 Error 페이지를 이미지를 다운로드
git clone https://github.com/kenmoini/custom-nginx-ingress-errors
cd custom-nginx-ingress-errors
tree
.
├── 404-screenshot.png
├── Dockerfile
├── README.md
├── hooks
│   └── pre_push
├── k8s-deployment.yaml
└── www
    ├── 404.html
    ├── 500.html
    ├── 503.html
    └── css
        └── style.css

# 사용자 정의 default-backend-service를 설정(에러 페이지 출력되는 파드)
kubectl apply -f k8s-deployment.yaml

# 확인
kubectl get pod -n ingress-nginx -l app.kubernetes.io/name=nginx-errors
NAME                            READY   STATUS    RESTARTS   AGE
nginx-errors-6fc8d6dfb9-g469w   1/1     Running   0          45s

kubectl get svc -n ingress-nginx nginx-errors
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
nginx-errors   ClusterIP   10.102.71.33   <none>        80/TCP    54s

# custom-http-errors 관련 설정을 적용하여 nginx 재배포
curl -O https://raw.githubusercontent.com/gasida/KANS/main/6/nginx-ingress.yaml
grep allow-snippet-annotations nginx-ingress.yaml
sed -i'' -r -e "/allow-snippet-annotations/a\  custom-http-errors: \"404,500,503\"" nginx-ingress.yaml
sed -i'' -r -e "/v=3/a\            - --default-backend-service=\$(POD_NAMESPACE)\/nginx-errors" nginx-ingress.yaml
kubectl apply -f nginx-ingress.yaml

# 테스트용 서비스/파드 배포
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

# ingress 정책에 503 에러를 발생시키키 위해서 없는 서비스 등록
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
      - path: /error
        pathType: Prefix
        backend:
          service:
            name: error
            port:
              number: 8080
EOT
kubectl apply -f  ingress1.yaml

# ingress-nginx-controller NodePort(HTTP 접속용) 변수 지정
export IngHttp=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
echo $IngHttp

# 접속 확인 : 웹 브라우저에서 접속
MASTER=192.168.10.10
curl $MASTER:$IngHttp -v

# 404 Error 확인 : 정의 되지 않은 /hello 를 호출해서 404 Error 발생
curl -D- -H 'Accept: application/json' $MASTER:$IngHttp/hello ;echo
HTTP/1.1 404 Not Found
Date: Tue, 08 Mar 2022 08:34:11 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive

{ "message": "The page you're looking for could not be found" }

# 503 Error 확인 : svc1-web 연결된 파드를 0 으로 설정하여 503 Error 발생
curl -D- -H 'Accept: application/json' $MASTER:$IngHttp ;echo
kubectl scale deployment deploy1-websrv --replicas=0
curl -D- -H 'Accept: application/json' $MASTER:$IngHttp ;echo

Untitled

Ingress Redirection

ingress nginx controller에서 지원하는 기능중 redirect 관련 설정을 찾아 요약해보았습니다.

  1. 영구 리디렉션 (Permanent Redirect)
    • nginx.ingress.kubernetes.io/permanent-redirect: 이 주석은 클라이언트에게 요청된 리소스가 새로운 URL로 영구적으로 이동되었다는 것을 알립니다. HTTP 상태 코드 301을 반환하며, 이후 클라이언트는 해당 URL로 직접 요청을 보내도록 합니다. 이 주석의 값이 https://www.google.com으로 설정되면 모든 요청은 https://www.google.com로 리다이렉트 됩니다.
  2. 영구 리디렉션 코드 (Permanent Redirect Code)
    • nginx.ingress.kubernetes.io/permanent-redirect-code: 이 주석은 영구적 리디렉션을 수행할 때 사용되는 HTTP 상태 코드를 변경하게 해줍니다. 기본값은 301이지만, 이 주석을 사용하면 다른 상태 코드로 변경할 수 있습니다. 예를 들어, nginx.ingress.kubernetes.io/permanent-redirect-code: '308'로 설정하면 308 상태 코드를 사용하여 영구 리다이렉션을 반환합니다. 이 코드는 원래 요청이 GET이 아니었을 경우에도 동일한 방식으로 요청을 유지하도록 웹 브라우저에 지시합니다.
  3. 임시 리디렉션 (Temporal Redirect)
    • nginx.ingress.kubernetes.io/temporal-redirect: 이 주석은 임시적 리디렉션, 즉 HTTP 상태 코드 302를 반환하도록 설정합니다. 이는 클라이언트에게 요청된 리소스가 일시적으로 다른 위치로 이동 되었음을 알리며, 클라이언트는 이후 동일한 URL로 요청을 계속 보낼 것입니다. 예를 들어, 이 주석의 값이 https://www.google.com으로 설정되면 모든 요청은 일시적으로 https://www.google.com로 리다이렉트 됩니다.

Ingress Nginx 설정으로 Prometheus Web 접근제한하기

사실 이 방법은 Prometheus 서비스랑 아무 관련이 없다.

Ingress는 쿠버네티스에 올라가있는 컨테이너들을 Cluster IP로 묶어도, Ingress Controller만 NodePort로 오픈이되어있으면, 해당 포트로 접근을 할 수 있으니 참 편한 세상이라고 할 수 있다!!?

이 문서는 Ingress Nginx Controller를 사용했을때, 내부 서비스를 Ingress로 노출할때 설정을 통해 nginx에서 접근제한을 설정하는 방법이다.

htpasswd Apache HTTP 서버에서 사용하는 도구로, 기본 인증(Basic Authentication)을 사용할 때 암호화된 사용자 이름과 비밀번호를 저장하는 파일을 생성하고 관리하는 데 사용된다

주요 명령어& 옵션

  • c: 새로운 .htpasswd 파일을 생성
  • b: 명령행에서 바로 사용자 이름과 비밀번호를 입력하여 파일에 추가
  • B: 비밀번호를 bcrypt 암호화 방식으로 저장
  • C: MD5 암호화를 사용할 때의 비용(cost)을 설정
htpasswd auth user1

명령어를 수행하면 user1 계정에 대해 비밀번호를 입력하는 화면을 보여준다

명령어에서 지정해준대로 auth라는 파일에 user / 암호화된 내용을 볼 수 있다.

해당 파일로 쿠버네티스 및 ingress-nginx 에서 사용을 하기위해 secret 으로 생성을 해준다.

kubectl create secret generic basic-auth --from-file=auth

만약 데이터의 변경이 된다면 secret을 업데이트 해줘야한다

그리고 해당 secret들이 마운트되어있는 pod도 재시작을 해줘야한다

configmap으로 선언한경우, 특정 pod들엔 reload 메카니즘이있다면 재시작을 하지않아도된다고하지만, secret은 그런게 없는거같다

이제 해당 secret을 생성 / 업데이트를 하여 ingress의 annotation에 업데이트를 진행한다.

추가할 코드는 다음과 같다.

    nginx.ingress.kubernetes.io/auth-realm: Authentication Required
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-type: basic

위 annotaion을 추가한 prometheus의 ingress 파일은 다음과 같은 형식이다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheus-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
  rules:
  - host: prometheus.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus-service
            port:
              number: 9090

ingress파일에 작성한대로 해당 주소에 로그인을 하게될경우

image.png

멘트를 조우할수있다.

로그인을 진행하면 기존에 사용하던 프로메테우스 web으로 접속했던 화면을 볼 수 있습니다.

Host network 사용

Cluster에 들어오는 Traffic을 nodeport로만 오픈해서 사용하는게 당연하다고 생각했다.

그것이 L4 구현체인 Service의 기본적인 기능들로 구현하는 방법이니깐…

사실 그냥 노드의 80/443 포트를 점유하면 되는데 왜 그런생각을 못해봤는지 모르겠습니다.

홉 떄문에라도 일부 Daemonset 형태의 애드온들은 host network를 사용하는 친구들이 이미 많거든요.

이 기회에 ingress controller에서 노드의 80/443 노드를 사용하는 방법을 찾아봤습니다.

cvalues.yaml

controller:
  service:
    annotations: {}
    type: ClusterIP
    httpPorts:
      - name: http
        port: 80
        targetPort: 80
      - name: https
        port: 443
        targetPort: 443
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet

간단한 ingress controller 의 value 파일입니다.

helm 파일을 작성할떄는 대부분 configuration이 필요하지 않은 옵션들이 이미 default로 들어가있기때문에, 필요한 부분만 직접 수정해서 쓰면 되니깐요


helm upgrade --install my-ingress-nginx ingress-nginx/ingress-nginx --version 4.11.3 -f cvalues.yaml

형태로 helm 설치를 진행하면 값들이 적용됩니다.

이후에 설정했던 ingress 파일의 도메인

그리고 etc host 를 수정해서 간단하게 nginx 를 띄워봅니다


---
apiVersion: v1
kind: Namespace
metadata:
  name: web-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: web-app
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
---
# Ingress 리소스
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: web-app
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com  # 처리할 도메인
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service  # 연결할 서비스 이름
            port:
              number: 80  # 서비스 포트

image.png

예전에 언젠간 설정해놨던 api 요청을 위한 etc 파일에 이미 api.example.com 에 대해 등록이 되어있어 접속 요청을 해보면 확인을 할 수 있겠죠

image.png

짜잔 완성입니다

정리하며

ingress controller에 다양한 애드온들을 활용하여 인증/인가를 포함한 추가적인 확장성들을 부여할수있습니다.

필요할경우 ingress controller에 body size나 redirection 외에도 정말 수많은 L7 확장이 가능하지만, Gateway API를 이용하여 추가적인 한계점들을 확장해나가는데에선 gateway api를 더 중요하게 공부해봐야하는게 아닐까 싶습니다.

© 2024 mont kim   •  Powered by Soopr   •  Theme  Moonwalk