Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

환경

  • 이 문서는 Kubernetes Ingress를 다룬다. NodePort와 LoadBalance는 참고 목적으로 다룰 것이다.
  • 우분투리눅스 20.4
  • minikube
로컬에 구축되는 minikube는 실제 클러스터를 구축하는게 아니기 때문에 CluseterIP를 외부에 노출 할 수 없다. minikube tunnel 을 실행 하자.
# minikube tunnel
Status:	
	machine: minikube
	pid: 14244
	route: 10.96.0.0/12 -> 192.168.49.2
	minikube: Running
	services: []
    errors: 
		minikube: no errors
		router: no errors
		loadbalancer emulator: no errors

Kubernetes Ingress

쿠버네티스 인그레스는 외부 사용자가 쿠버네티스 클러스터에서 실행중인 서비스에 접근하기 위한 방법을 제어하는 라우팅 규칙 모음이다. 일반적으로 HTTP를 관리한다. 용어를 확인하고 넘어가자.
  • 노드(Node) : 쿠버네티스 클러스터를 구성하는 노드들이다. 이 노드들에 애플리케이션 컨테이너가 실행된다.
  • 클러스터 : 쿠버네티스 노드들의 집합이다. 클러스터를 구성하는 노드들은 일반적으로 퍼블릭 네트워크(인터넷)으로 부터 격리된다.
  • 클러스터 네트워크(Cluster Network) : 쿠버네티스 네트워킹 모델에 따라 클러스터 내부에서 사용하는 네트워크 집합.
  • 서비스(Service) : 레이블 셀렉터를 사용해서 Pod 집합으로 구성된 쿠버네티스 서비스다. 보통 서비스는 클러스터 네트워크에서만 라우팅 가능한 가상 IP를 가진다.
Ingress는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출한다. 트래픽은 Ingress 리소스에 정의된 규칙에 의해서 컨트롤 된다. Ingress 리소스라는 단어가 들어가서 어렵게 생각 할 수 있는데, 딱 로드밸런서라고 생각하면 된다.

아래는 Ingress가 트래픽을 여러 서비스로 보내는 것을 묘사하고 있다. 로드밸런서와 차이가 없음을 알 수 있다.

 Ingress 묘사

Ingress는 임의의 포트 또는 프로토콜을 노출시키지 않는다. 보통은 Service.Type=NordPort, Service.Type=LoadBalancer 유형의 서비스와 함께 사용한다.

NodePort

NodePort는 그 이름에서 알 수 있듯이, 클러스터를 구성하는 Node와 애플리케이션 Port로 직접 접근하는 것으로 가장 원시적인(primitive)한 방법이다.

 NodePort

아래는 NodePort를 지원하는 Service의 스펙이다.
apiVersion: v1
kind: Service
metadata:  
  name: my-nodeport-service
spec:
  selector:    
    app: my-app
  type: NodePort
  ports:  
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30036
    protocol: TCP

Load Balancer

LoadBalancer 서비스 타입은 외부 로드밸런서를 이용하는 방식이다. 외부 로드밸런서는 NginX, AWS ALB(Application Load Balancer), Kong, Traefik 무엇이든 상관없다.

 Load Balancer Type

이 로드밸런서에는 공인 IP주소가 할당되고 외부 트래픽을 클러스터의 쿠버네티스 서비스로 라우팅한다. 요즘 클라우드에 쿠버네티스 클러스터를 전개하는 경우가 많아지고 있는데, 대부분의 클라우드 서비스 제공자는 자사에서 제공하는 로드밸런스 서비스를 쿠버네티스에 통합 할 수 있게 제공한다. 클라우스 서비스를 이용하고 있다면, 클라우스 서비스 제공자가 제공하는 로드밸런서를 이용하는게 확장성/안정성 측면에서 유리하다.

Ingress

쿠버네티스는 호스트 혹은 URL을 기반으로 작동하는 Ingress를 제공한다. Ingress는 Ingress controller를 이용해서 Nginx, Kong, Traefik와 같은 타사 프록시를 제어하는 방식으로 구현되어 있다.

Ingress 컨트롤러는 쿠버네티스 클러스터 레벨에서 작동하는 프락시로 쿠버네티스와 매우 밀접하게 통합되어 있다. 쿠버네티스 클러스터 관리자는 목적에 맡는 프락시를 이용해서 클러스터내에서의 로드밸런싱을 구축할 수 있다. 쿠버네티스 ingress는 쿠버네티스 클래스터 레벨에서 작동하므로 여전히 외부 로드밸런서가 필요 할 수 으며, 보통 외부 로드밸런서와 함께 구축 한다. 아래 그림은 쿠버네티스 ingress를 묘사하고 있다.

 Ingress

Ingress(NginX, Istio 등으로 구성된)로 HTTP 요청이 들어오면, 이 요청은 각 프락시 설정에 따라서 서비스로 라우팅된다.

Use Case

NginX Ingress

쿠버네티스 ingress 리소스가 작동하려면 클러스터에 Ingress 컨트롤러가 있어야 한다. 여기에서는 NginX ingress 컨트롤러를 설치하기로 했다. Nginx Ingress Controller Installation Guide문서를 참고해서 설치했다.

# minikube addons enable ingress
    ▪ Using image k8s.gcr.io/ingress-nginx/controller:v0.44.0
    ▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
    ▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
Verifying ingress addon...
'ingress' 애드온이 활성화되었습니다

클러스터 상태를 확인해보자.
# kubectl get pods -A
NAMESPACE       NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx   ingress-nginx-admission-create-bhwkp        0/1     Completed   0          19h
ingress-nginx   ingress-nginx-admission-patch-btbf8         0/1     Completed   0          19h
ingress-nginx   ingress-nginx-controller-59b45fb494-bqn57   1/1     Running     1          19h
kube-system     coredns-558bd4d5db-v6dc7                    1/1     Running     2          37h
kube-system     etcd-minikube                               1/1     Running     2          37h

apple 서비스를 실행하자.
kind: Pod
apiVersion: v1
metadata:
  name: apple-app
  labels:
    app: apple
spec:
  containers:
    - name: apple-app
      image: hashicorp/http-echo
      args:
        - "-text=apple"

---

kind: Service
apiVersion: v1
metadata:
  name: apple-service
spec:
  selector:
    app: apple
  ports:
    - port: 5678 # Default port for image
# kubectl apply -f ./apple.yaml     
pod/apple-app created
service/apple-service created

banana 서비스를 실행하자.
kind: Pod
apiVersion: v1
metadata:
  name: banana-app
  labels:
    app: banana
spec:
  containers:
    - name: banana-app
      image: hashicorp/http-echo
      args:
        - "-text=banana"

---

kind: Service
apiVersion: v1
metadata:
  name: banana-service
spec:
  selector:
    app: banana
  ports:
    - port: 5678 # Default port for image
# kubectl apply -f ./banana.yaml
pod/banana-app created
service/banana-service created

각 서비스들이 잘 실행됐는지 확인하자.
# kubectl get pod -l app=apple
NAME        READY   STATUS    RESTARTS   AGE
apple-app   1/1     Running   0          3m18s

# kubectl get pod -l app=banana
NAME         READY   STATUS    RESTARTS   AGE
banana-app   1/1     Running   0          40s

각 서비스들의 ClusterIP를 확인해 보자.
# kubectl get service apple-service
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
apple-service   ClusterIP   10.102.31.232   <none>        5678/TCP   6h16m

# kubectl get service banana-service
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
banana-service   ClusterIP   10.102.252.63   <none>        5678/TCP   6h13m

apple-service의 상세정보를 확인하자.
# kubectl describe service apple-service      
Name:              apple-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=apple
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.102.31.232
IPs:               10.102.31.232
Port:              <unset>  5678/TCP
TargetPort:        5678/TCP
Endpoints:         172.17.0.4:5678
Session Affinity:  None
Events:            <none>

여기에서 주목할 것은 CluseterIP인 10.102.31.232와 Pod IP인 172.17.0.4 이다. 아래와 같이 apple-service에 접근 할 수 있다.
# curl 10.102.31.232:5678
apple

banana-service 도 상세정보 확인해서 접근 테스트를 해보자.
# kubectl describe service banana-service
Name:              banana-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=banana
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.102.252.63
IPs:               10.102.252.63
Port:              <unset>  5678/TCP
TargetPort:        5678/TCP
Endpoints:         172.17.0.5:5678
Session Affinity:  None
Events:            <none>

# curl 10.102.252.63:5678
banana

Ingress 리소스 생성

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
        - path: /apple
          backend:
            serviceName: apple-service
            servicePort: 5678
        - path: /banana
          backend:
            serviceName: banana-service
            servicePort: 5678

Ingress 리소스를 생성한다.
# kubectl apply -f ./ingress.yaml
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.extensions/example-ingress created

Ingress 리소스 정보를 확인해보자.
# kubectl get ing 
NAME              CLASS    HOSTS   ADDRESS        PORTS   AGE
example-ingress   <none>   *       192.168.49.2   80      60s

kubectl describe ing example-ingress
Name:             example-ingress
Namespace:        default
Address:          192.168.49.2
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /apple    apple-service:5678 (172.17.0.3:5678)
              /banana   banana-service:5678 (172.17.0.2:5678)
Annotations:  ingress.kubernetes.io/rewrite-target: /
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    25m (x2 over 25m)  nginx-ingress-controller  Scheduled for sync

Ingress 서비스를 확인해보자.
# kubectl get svc -n ingress-nginx 
NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.106.46.180   <none>        80:30098/TCP,443:30722/TCP   30h
CLUSTER-IP로 접근테스트를 해보자.
# curl 10.106.46.180/apple
apple

# curl 10.106.46.180/banana
banana

AWS NLB와 NginX Ingress Controller

AWS의 Network Load Balancer를 이용해서 Kubernetes를 인터넷에 노출해보자. 여기에서는 실제 테스트는 하지 않고 개념 설명만 할 것이다.

AWS의 Network Load Balancer는 OSI 4계층에서 작동한다. 구조가 단순한 만큼 AWS의 Application Load Balancer이나 Classic Load Balancer 보다 더 많은 요청을 처리 할 수 있다. 고정 IP를 할당 할 수 있기 때문에, 고정 IP를 외부에 제공해야 하는 경우 (B2B 비즈니스에서 필요한 경우가 있음) 사용한다.

구조는 아래와 같다.

 NLB Nginx Ingress

이 구성은 그다지 일반적이지 않은 구성일 수 있다. ALB Ingress Controller를 이용하는게 더 효과적으로 보이기 때문이다. 아래 이미지는 ALB Ingress Controller를 이용한 구성이다. NginX Ingress Controller대신 ALB Ingress Controller를 사용한 것이기 때문에 구조적인 차이는 없다.

 ALB Ingress Controller

대부분의 경우에는 ALB Ingress Controller가 더 나은 옵션일 것이다. NLB 는 아래와 같은 경우에 이점을 제공한다.
  • 고정된 IP 제공
  • 성능 : 수백만개의 요청으로 쉽게 확장될 수 있다.
  • 소스/목적지 주소 보존 : OSI 4계층이므로 소스/목적지 주소를 보존할 수 있다.
  • Long-live TCP 연결 지원 : OSI 4계층에서 작동하기 때문에 가능한 기능이다. 몇일, 몇달 동안 오픈된 TCP 연결을 지원한다. WebSocket 유형의 애플리케이션, IoT, 게임, 메시징 애플리케이션에 이상적이다.
  • 대역폭 사용량 감소 : Application Load Balancer, Classic Load Balancer에 비해서 약 25% 정도의 비용 절감 효과를 볼 수 있다.

참고