쿠버네티스 교육

08. Kube 교육 - NodePort, LoadBalancer

Jerry_이정훈 2021. 6. 4. 16:41
728x90

실습

  • Nodeport 사용하여 외부에서 POD 접속해 보세요
    : nodeport 를 특정 Port로 지정해 보세요. 
  • MetalLB 설치 
  • LoadBalancer 사용하여 POD 접속하기 
  • LoadBalancer IP를 특정 IP로 할당하고 동일 IP로 2개의 Protocol(TCP, UDP)를 할당해 보세요

Why NodePort, LoadBalancer?

NGINX 웹 서버를 설치하고 나면 당연히 내 PC에서 웹 서버로 정상적으로 접속이 되는지 검증하고 싶습니다. 하지만 Kube POD는 노드 안에서 실행되는 거라 노드 안에 있는 POD를 외부에서 바로 접속할 수 있는 방법이 없습니다. (D-NAT 등의 추가 네트워크 설정이 필요합니다.) 노드의 IP와 POD의 IP는 서로 다른 대역이라 다이렉트 통신이 안 됩니다. 

 

그래서 Kube에서는 POD로 접속하는 방법으로 아래 3가지를 제공합니다

  • Service : NodePort, LoadBalancer
  • Ingress

 

NodePort

(이번 포스팅에서는 Service NodePort, LoadBalancer만 다루고 Ingress는 Traefik 포스팅에서 설명 하겠습니다. )

 

Service NodePort란? 

외부 Traffic이 이름 그대로 NodePort, 물리 Node(VM, 혹은 Baremetal)의 특정 Port를 이용하여 내부 POD와 통신하는 방법을 의미합니다. 서비스에서 NodePort를 사용하기 위해서는 spec.type 부문을 NodePort로 변경하면 됩니다. 

NodePort 에서 사용하는 Port 대역은?
Default로 30000 ~ 32767 Port 대역을 사용 합니다.

NodePort로 사용하는 Port를 특정 Port로 지정하는 방법은? 

Service YAML 파일, spec.ports.nodePort로 특정 Port를 지정합니다. (만약 해당 Port가 이미 사용 중이면 에러가 발생합니다.) 특별히 nodePort를 지정하지 않으면 30000 ~ 32767 Port 중 하나를 random하게 할당합니다. 그러면 매번 재시작 시 계속 변경되어 불편합니다. 

 

그럼, NodePort 실습해 보겠습니다.

 

기존 실행 중인 NGINX POD가 있으면 그대로 활용하시고 삭제를 하셨으면 신규로 다시 만들어 줍니다. 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx  # Deploy Label 이름 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx  # Service에서 사용할 Label 
    spec:
      containers:
      - name: nginx
        image: nginxdemos/hello
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: nginx
spec:
  type: NodePort
  ports:
  - name: tcp
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080 # 원하는 port 번호로 고정합니다.
  selector:  # 선택해야 할 POD 선택
    app: nginx  # POD Label 과 동일
[spkr@erdia22 41.NGINX (k3s:nginx)]$ ka nginx-deploy.yml 
deployment.apps/nginx-deployment created

[spkr@erdia22 41.NGINX (k3s:nginx)]$ ka nginx-svc.yml 
service/nginx-svc created

정상적으로 생성이 되면 endpoint 확인이 가능합니다.

[spkr@erdia22 41.NGINX (k3s:nginx)]$ k get endpoints
NAME        ENDPOINTS        AGE
nginx-svc   10.42.0.155:80   6s

적용된 NodePort Port는 Service 리스트로 확인 가능합니다.

k [spkr@erdia22 ~ (k3s:nginx)]$ k get svc
NAME        TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
nginx-svc   NodePort   10.43.26.55   <none>        80:30080/TCP   2m38s

위 서비스 내역의 PORT(S) 30080 Port가 NodePort 입니다. 이제 이 포트로 접속하면 NGINX 웹 서비스 확인이 가능합니다.

[spkr@erdia22 ~ (k3s:nginx)]$ k get nodes -o wide
NAME                    STATUS   ROLES                  AGE   VERSION        INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
localhost.localdomain   Ready    control-plane,master   14d   v1.20.7+k3s1   172.17.29.166   <none>        CentOS Linux 7 (Core)   3.10.0-1062.12.1.el7.x86_64   containerd://1.4.4-k3s1

Node IP는 위와 같이 확인 합니다. 이제 웹브라우저에서 확인해 보겠습니다. 

위와 같이 정상적으로 웹브라우저에서 확인 가능합니다. 

 

NodePort 제약 사항은?

: 외부 고객, 클라이언트가 웹 서버 접속 시 80, 443 등 Well-known port 가 아닌 30000 ~ 32767 Port를 사용해야 합니다. 따라서 실 운영 환경이라면 NodePort를 사용하지 않고 LoadBalancer Service Type, 또는 Ingress, or 물리 L4 스위치를 사용합니다. 

 

외부의 L4 스위치 사용 시 Target IP, Port는 어떻게 지정할까요?
: 단일 노드가 아닌 전체 노드의 IP와 NodePort Port 등록합니다. 복수 노드를 선택하므로 HA 구성이 가능합니다. 

 

Service LoadBalancer란?

외부에서 들어오는 Traffic 등을 별도의 외부 Object를 통하여 Traffic을 분산시키는 것을 LoadBalancer라고 합니다. (설명이 너무 부실하네요…) 기존 물리 L4 스위치가 traffic을 분산 시키는 것과 유사하다고 생각하시면 될 것 같습니다. 

공식 홈페이지 인용
LoadBalancer: Exposes the Service externally using a cloud provider's load balancer. NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created.

LoadBalancer: 클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킨다. 외부 로드 밸런서가 라우팅되는 NodePort와 ClusterIP 서비스가 자동으로 생성된다.

공식 홈페이지는 클라우드 공급자라고 명시하는데 실제로는 Public Cloud(aws, azure, gcp)가 아닌 Local On-Prem 환경에서도 MetalLB 등을 통하여 LoadBalancer 기능을 구현 가능합니다.

 

LoadBalancer 설치

On-Prem 환경에 사용 가능한 LoadBalancer로 대표적으로 MetalLB가 있습니다. (MetalLB 설치는 K3S 환경에서 지원하지 않습니다. K3S 설치 시 같이 설치되는 Traefik Ingress 사용합니다.)

MetalLB 설치는 아주 간단합니다. 
: 공식 홈피 참조, https://metallb.universe.tf/installation/

 

MetalLB, bare metal load-balancer for Kubernetes

Installation Before starting with installation, make sure you meet all the requirements. In particular, you should pay attention to network addon compatibility. If you’re trying to run MetalLB on a cloud platform, you should also look at the cloud compat

metallb.universe.tf

kubectl edit configmap -n kube-system kube-proxy
: stricARP false to true 변경 

 

: kube-proxy restart 
kubectl rollout restart -n kube-system daemonset kube-proxy

[user@git ~]$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/namespace.yaml
namespace/metallb-system created

[user@git ~]$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/metallb.yaml
podsecuritypolicy.policy/controller created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
role.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
daemonset.apps/speaker created
deployment.apps/controller created

[user@git ~]$ kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
secret/memberlist created

POD 확인

[user@git ~]$ k get pod -n metallb-system
NAME                          READY   STATUS    RESTARTS   AGE
controller-65db86ddc6-bt6rg   1/1     Running   0          55s
speaker-2xsnx                 1/1     Running   0          55s
speaker-r4kp4                 1/1     Running   0          55s
speaker-xpgfg                 1/1     Running   0          55s

설치가 정상적으로 완료 되었습니다. 

 

이제 LoadBalancer 에서 사용할 IP 대역을 추가해 보겠습니다. IP 추가는 MetalLB ConfigMap을 사용 합니다. IP는 외부에서 접속 가능한 IP 대역으로 할당합니다.

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.146 - 192.168.1.151 # IP 대역 지정 
#      - 192.168.1.152 - 192.168.1.152 # 단일 IP 시 지정 방법 

서비스 Type을 LoadBalancer 로 지정하여 생성하세요.

apiVersion: v1
kind: Service
metadata:
  name: nginxhello-svc
  # namespace: default
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-hello
  sessionAffinity: None
  type: LoadBalancer

서비스 확인 

[spkr@erdia22 06.Deployment (spkn02:nginx)]$ k get svc
NAME             TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE
nginxhello-svc   LoadBalancer   10.233.9.86   172.17.28.160   80:32240/TCP   5d20h

TYPE LoadBalancer로 정상적으로 생성이 되었습니다. 이제 외부에서 접속해 보겠습니다. 

(물론 ^^) 정상적으로 잘 됩니다.

 

특정 IP 주소를 LoadBalancer IP로 할당하세요.
동일 IP에 2개의 Protocol(UDP, TCP)를 할당하세요.


spec.loadBalancerIP를 이용하여 특정 IP 지정이 가능합니다. 그리고 2개의 Serivce에서 annotations(allow-shared-ip)을 같이 지정하여 동일 IP + 2개의 Protocol 가지는 Service 생성이 가능합니다.  

apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: traefik
    meta.helm.sh/release-namespace: traefik
    metallb.universe.tf/allow-shared-ip: 192.168.1.146
    service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true"
  labels:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: traefik
    helm.sh/chart: traefik-9.17.2
  name: traefik
  namespace: traefik
spec:
  externalTrafficPolicy: Local
  loadBalancerIP: 192.168.1.146
  ports:
  - name: traefik
    nodePort: 32246
    port: 9000
    targetPort: traefik
  selector:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/name: traefik
  sessionAffinity: None
  type: LoadBalancer

apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: traefik
    meta.helm.sh/release-namespace: traefik
    metallb.universe.tf/allow-shared-ip: 192.168.1.146
  labels:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: traefik
    helm.sh/chart: traefik-9.17.2
  name: traefik-udp
  namespace: traefik
spec:
  externalTrafficPolicy: Local
  loadBalancerIP: 192.168.1.146
  ports:
  - name: jvb-udp
    protocol: UDP
    port: 10000
    targetPort: 10000
  selector:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/name: traefik
  sessionAffinity: None
  type: LoadBalancer

확인을 해보면

[spkr@erdia22 06.Deployment (dzbumin:nginx)]$ k get svc -n traefik
NAME          TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)
  AGE
traefik       LoadBalancer   10.233.43.121   192.168.1.146   9000:32246/TCP,80:32299/TCP,443:30933/TCP,54321:32195/TCP,11887:30976/TCP,4443:31583/TCP   18h
traefik-udp   LoadBalancer   10.233.9.219    192.168.1.146   10000:30545/UDP
  18h

위와 같이 192.168.1.146 IP로 2개의 Protocol(TCP, UDP)를 사용하는 Service가 생성되었습니다. 외부에서 TCP, UDP 둘 다 접속 가능합니다.

 

참조

https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0

 

Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?

Recently, someone asked me what the difference between NodePorts, LoadBalancers, and Ingress were. They are all different ways to get…

medium.com

 

반응형