티스토리 뷰

Cloud/Kubernetes

kubernetes ingress

jacobbaek Jacob_baek 2021. 3. 15. 21:14

ingress를 처음 사용해보려 했을때 external IP에 대한 궁금증이 생겼었다.
이유는 맨처음 접했을때에는 ingress가 external IP까지 다 만들어줄거라 착각을 했었다.
(실제 ingress랑 nodeport, loadbalancer를 하나의 페이지에서 소개하는것을 같은 기능을 제공하는줄 착각했었다.)

알다시피 ingress는 External IP까지 만들고 관리해주지 않는다.
대신 reverse proxy 같은 개념으로 kubernetes 에 동작되는 모든 application이 ingress를 경유해서 외부에서 접근 될수 있도록 만들수 있고 필요에 따라 보안설정, 인증서 적용 등 ingress를 이용해 다양한 방식의 추가 서비스를 제공할수 있게 된다.

그럼 이런 ingress에 대해 간단히 알아보고 궁금했던 external IP 에 대해서도 어떻게 사용이 가능한지 알아보도록 하자.

NOTE
해당 환경은 baremetal 환경에 기반하여 진행된 내용이기에 public cloud 환경에서는 다를수 있음을 인지하길 바란다.

Ingress란

ingress에 대한 소개는 다음 링크에 상세히 나와 있다. 한번 정독해보기를 권장한다.

여러종류의 ingress가 있다.

  • nginx-ingress
  • treafik ingress
  • istio
  • ...

여기서는 ingress로 필자가 처음접한 nginx-ingress에 대하여 알아보도록 하겠다.
(사실 nginx가 좀더 친숙해서 별다른 기준없이 선택하였다.)

nginx ingress

nginx-ingress를 설치하고 간단히 사용하는 방법을 알아보자.
helm을 이용한 설치는 아주 간단하다.
(참고로 아래 예제는 helm version 3로 진행되었다.)

아래와 같이 helm chart repo를 추가하고 install을 진행한다.

jacob@jacob-laptop:~$ helm repo add bitnami https://charts.bitnami.com/bitnami
jacob@jacob-laptop:~$ helm install nginx bitnami/nginx-ingress-controller -n kube-system

설치후 LB를 별도로 구축한 경우는 ingress controller의 service가 LoadBalancer Type으로 자동 생성되어 외부 접근이 가능해진다.
LB를 구성하지 않은 경우는 nodeport type으로 구성해서 테스트 해보기를 권장한다.
LB(metallb)가 구성된 환경에서 아래와 같이 ingress-controller의 service가 external-ip를 binding 한것을 확인 할수 있다.

jacob@jacob-laptop:~$ kubectl get svc -n kube-system
NAME                                             TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
coredns                                          ClusterIP      10.233.0.3      <none>            53/UDP,53/TCP,9153/TCP       3d3h
nginx-nginx-ingress-controller                   LoadBalancer   10.233.17.184   192.168.1.100   80:30828/TCP,443:30366/TCP   138m
nginx-nginx-ingress-controller-default-backend   ClusterIP      10.233.48.82    <none>            80/TCP                       138m

참고로 nginx-stable에 있는 helm chart의 경우 아래와 같이 최신버전(1.19.x 이상)으로 설치시 아래와 같은 warning message를 출력하게 된다. 생각되기론 관리가 제대로 되지 않는 느낌이다. 하여 bitnami repo를 사용하는것을 추천한다.

[root@deploy ~]# helm install nginx nginx-stable/nginx-ingress -n kube-system
W0315 16:30:48.347957 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.376382 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.388206 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.397170 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.407844 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.421366 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
W0315 16:30:48.442353 3382676 warnings.go:70] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition

이제 구성이 되었으니 ingress를 사용해보자.
아래와 같은 yaml 혹은 helm chart의 경우 대개 ingress 설정을 지원하기에 chart에 맞는 ingress 구성을 하면 된다.

apiVersion: extensions/v1
kind: Ingress
metadata:
  name: test-ingress
  name: test
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
        - path: /
          backend:
            serviceName: test-service
            servicePort: 8080

위 설정은 외부에 노출시키려는 Application이 사용중인 service(아래 예제참고)를 backend로 두고 외부에서 /(별도의 url내 directory 입력 없음)로 접근시 외부에 노출시키려는 Application에 forwarding 시키는 방식이라 보면 된다.

jacob@jacob-laptop:~$ kubectl get svc -n test
NAMESPACE         NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
test              test-service         ClusterIP      10.233.25.106   <none>            8080/TCP                    3d2h

external IP 할당 및 관리

먼저 Kubernetes 환경에서 external ip를 사용하려면 다음과 같은 방식 중 하나를 선택해야 한다.

여기서 LoadBalancer Type이 아닌 NodePort 같은 다른 Type은 서비스에는 사용되기 어렵다.
(이유는 임의의 특정 port(3xxxx or 4xxxxx)를 binding 하는데 일반적인 서비스용으로 domain:3xxxx 와 같은 서비스를 launching하는것은 적합해보이지 않기 때문이다.)

하여 MetalLB를 이용한 환경을 알아보도록 하겠다.

metallb install and configuration

metallb 는 kubernetes Service resource에 LoadBalancer type을 사용할수 있도록 해준다.
L2 layer mode와 BGP mode가 있으며

  • l2 layer mode는 arp/ndp와 같은 protocol을 이용하여 LAN(Layer 2)에서 지정된 IP를 사용할수 있게 해준다.
  • BGP mode는 상단의 network router와 구성된 kubernetes간에 routing 정보 교환이 가능한 모드로 좀더 확장된 개념이라 볼수 있다.
  • metallb.universe.tf/concepts/

여기서는 l2 layer mode를 사용하는 metallb를 helm chart를 이용해 설치해보도록 하겠다.
helm을 이용한 설치는 아주 간단하다.
(참고로 아래 예제는 helm version 3로 진행되었다.)

아래와 같이 helm chart repo를 추가하고 install을 진행한다.

jacob@jacob-laptop:~$ helm repo add bitnami https://charts.bitnami.com/bitnami
jacob@jacob-laptop:~$ helm install metallb bitnami/metallb -n kube-system

배포된 configmap에 아래와 같이 사용할 address pool을 지정하면 앞으로 생성된 LoadBalancer Type을 가지는 service는 External IP를 앞서 지정한 address pool중에 하나의 IP를 할당받게 된다.

jacob@jacob-laptop:~$ kubectl get cm/metallb-config -n kube-system -o jsonpath='{.data.config}'
address-pools:
- name: default
  protocol: layer2
  addresses:
  - 192.168.1.100-192.168.1.200

만약 Service에 LoadBalancer Type으로 변경했음에도 ip 할당이 안되고 계속 pending 상태가 된다면 아래 명령을 통해 metallb controller의 상태를 확인해보면 힌트를 얻을 수 있다.

jacob@jacob-laptop:~$ kubectl logs `kubectl get po -n kube-system | grep metallb-controller | cut -d' ' -f 1` -n kube-system

haproxy and keepalived

keepalived 를 이용한 VIP을 할당하고 haproxy를 통한 load balancing을 수행한다.
이때 kubernetes 상에 application은 다음과 같은 방식으로 haproxy상에 server로 등록하게 된다.

  1. keepalived 로 VIP 생성
  2. kubernetes service 를 nodeport 변경
  3. nodeport로 변경한 service의 port와 각 master node의 IP를 기억하자.
  4. haproxy에 등록하기 위해 server로 앞서 기억된 node:port 조합을 입력하고 keepalived로 생성된 VIP을 listen IP로 등록한다.

개인적으로 위 구조는 매번 위와 같은 과정을 거쳐야 하기 때문에 이는 매우 비효율적인 방식이다.
하여 아래 설명할 ingress의 조합을 해당 방식은 필히 사용하는것을 권장한다.

Combination

앞서 이야기하였듯이 ingress 하나만 혹은 loadbalancer 하나만 가지고는 서비스를 할수 없다. 즉, 조합이 필요하다.
그렇다면 위에 설명한 ingress 및 Load Balancer 중 어떤 구성을 통해 외부에 서비스를 open할수 있을지 알아보자.
(아래 나열된 구조는 자체 경험했던 기반으로 기술하였다.)

metallb + nginx-ingress

metallb를 l2 layer mode로 동작시키고 nginx-ingress를 설치하여 ingress-controller의 service를 metallb 의 L2 layer mode상에 지정한 address pool중 하나의 IP로 지정한다.

metallb를 이용해 ingress에서 사용하는 IP말고 다른 IP를 할당할 수 도 있다.

haproxy + keepalived + nginx-ingress

앞서 설명했던 keepalived 를 이용해 VIP을 생성하고 해당 VIP을 haproxy에 listen 시키며
당시 사용할 server는 kubernetes에서 사용중인 nginx-ingress controller service의 nodeport port와 master IP 조합으로 구성한다.

예제로 좀더 이해를 돋구자면 아래와 같은 설정이 이루어지게 된다.

frontend nginx-ingress
  bind 172.16.100.100:443
  bind 127.0.0.1:443
  mode tcp
  option tcplog
  default_backend ingress-backends

backend ingress-backends
  mode tcp
  option tcplog
  option tcp-check
  balance roundrobin
  default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
  server master001 172.16.100.10:32323 check
  server master002 172.16.100.11:32323 check
  server master003 172.16.100.12:32323 check
  • VIP : 172.16.100.100
  • nodeport를 이용한 master node IPs : 172.16.100.10~12:32323

NOTE
위 내용들은 쉽게 접근이 가능한 내용들이며 필자가 경험했던 내용을 기반으로 작성한것들이며
실제 이외에도 다양한 외부 접근이 가능하게 만드는 방식이 있을거라 생각됩니다.
경험했던 좋은 구성이 있다면 공유해주시면 감사드리겠습니다.

참고사이트

'Cloud > Kubernetes' 카테고리의 다른 글

ingress with subpath  (0) 2021.03.23
Cluster-API  (0) 2021.03.20
kubernetes ingress  (0) 2021.03.15
Longhorn  (0) 2021.03.13
K3s with calico  (0) 2021.03.05
K3s  (0) 2019.11.17
댓글
댓글쓰기 폼