LoadBalancer 타입의 서비스

- 클라우드 환경에서는 로드밸런서 사용이 간편. 온프레미스 환경에서는 상당히 복잡하다.
현재는 클라우드를 사용하지 못하므로 온프레미스 환경에서 로드밸런서를 사용해본다.
온프레미스 환경에서 LoadBalancer 타입의 서비스를 연동
: 클러스터 내부에 로드밸런서 서비스를 받아 주는 구성이 필요한데.... => 이를 MetalLB가 담당한다.
1. MetalLB
: 쿠버네티스 클러스터 내에서 로드밸런싱을 제공하기 위한 오픈 소스 프로젝트이다.
클라우드 공급자에서 실행되지 않는 클러스터에서 LoadBalancer 유형의 쿠버네티스 서비스 생성이 가능해진다.
클러스터 내에서 외부에 라우팅 해주는 역할
- https://metallb.universe.tf/
2. 로드밸런서가 없는 환경에서 LoadBalancer 타입의 서비스 생성
- 서비스 생성을 위한 샘플 디플로이먼트 생성 및 확인 (yaml 파일 없이 쿠버네티스에서 생성)
> kubectl create deployment my-nginx --image=nginx
vagrant@controlplane:~$ kubectl create deployment my-nginx --image=nginx
deployment.apps/my-nginx created
> kubectl get pod (디플로이먼트 생성에 따라 생성된 파드 확인)
vagrant@controlplane:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-8474f7bd66-z74x6 1/1 Running 0 8s
- 로드밸런서 타입의 서비스 생성 및 확인
> kubectl expose deployment my-nginx --port 80 --type LoadBalancer
vagrant@controlplane:~$ kubectl expose deployment my-nginx --port 80 --type LoadBalancer
service/my-nginx exposed
> kubectl get service
vagrant@controlplane:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.17.0.1 <none> 443/TCP 2d18h
my-nginx LoadBalancer 172.17.47.214 <pending> 80:31134/TCP 7s
=> 로드밸런서가 존재하지 않기 때문에 pending 상태로 유지된다.
- 서비스 및 디플로이먼트 삭제
> kubectl delete deployment --all
vagrant@controlplane:~$ kubectl delete deployment --all
deployment.apps "my-nginx" deleted
> kubectl delete service --all
vagrant@controlplane:~$ kubectl delete service --all
service "kubernetes" deleted
service "my-nginx" deleted
> kubectl get all
vagrant@controlplane:~$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 172.17.0.1 <none> 443/TCP 13s
3. staticARP mode 활성화
> kubectl get configmap kube-proxy -n kube-system -o yaml sed -e "s/strictARP: false/strictARP: true/" kubectl apply -f -n kube-system
vagrant@controlplane:~$ kubectl get configmap kube-proxy -n kube-system -o yaml | \
> sed -e "s/strictARP: false/strictARP: true/" | \
> kubectl apply -f - -n kube-system
Warning: resource configmaps/kube-proxy is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/kube-proxy configured
* kubectl 명령어 입력 중 명령어 길이가 길어 입력 및 구분에 불편함이 있다면 "| \" 입력으로
명령어를 다음 줄로 넘길 수 있다.
4. MetalLB 설치
주소 URL: https://metallb.universe.tf/installation/
> kubectl apply -f https://raw.githubusercontent.com/metallb/v0.14.8/config/manifests/metallb-native.yaml
vagrant@controlplane:~$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
:
:
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
- metalLB-system이 제대로 설치되었는지 확인
> kubectl get all -n metallb-system
vagrant@controlplane:~$ kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/controller-8694df9d9b-zv4hx 1/1 Running 0 62s
pod/speaker-dxxg4 1/1 Running 0 62s
pod/speaker-f5ncm 1/1 Running 0 62s
pod/speaker-ww24t 1/1 Running 0 62s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metallb-webhook-service ClusterIP 172.17.62.14 <none> 443/TCP 62s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR
AGE
daemonset.apps/speaker 3 3 3 3 3 kubernetes.io/os=linux 62s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 62s
NAME DESIRED CURRENT READY AGE
replicaset.apps/controller-8694df9d9b 1 1 1 62s
5. 로드밸런스 서비스에 할당할 IP 대역을 정의
- Virtual Machine에서 메인 호스트 IP 어댑터의 DHCP 서버를 로드밸런스 서비스에서 활용할 수 있도록 활성화

- 로드밸런서에 할당하는 IP 대역폭을 정의하는 yaml 파일 생성
https://metallb.universe.tf/configuration/ 에서 yarml 파일의 내용을 가져온다.
IPAddressPool과 layer 2 configuration 을 가져와서 spec의 할당하는 주소의 대역폭만 바꿔주었다.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.0.0.3-10.0.0.254
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
- metalLB에 작성한 yaml 파일 적용
> kubectl apply -f routing-config.yaml -n matallb-system
vagrant@controlplane:~$ kubectl apply -f routing-config.yaml -n metallb-system
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/example created
- IP 대역폭이 설정되었는지 확인
> kubectl get IPAddressPool -n metallb-system
vagrant@controlplane:~$ kubectl get IPAddressPool -n metallb-system
NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
first-pool true false ["10.0.0.3-10.0.0.254"]
6. 디플로이먼트와 서비스를 생성해서 EXTERNAL-IP가 할당되는지 확인
- 디플로이먼트 & 서비스 생성 후 확인
> kubectl create deployment my-nginx --image=nginx
vagrant@controlplane:~$ kubectl create deployment my-nginx --image=nginx
deployment.apps/my-nginx created
> kubectl expose deployment my-nginx --port 80 --type LoadBalancer
vagrant@controlplane:~$ kubectl expose deployment my-nginx --port 80 --type LoadBalancer
service/my-nginx exposed
> kubectl get service,pod
vagrant@controlplane:~$ kubectl get service,pod
NAME READY STATUS RESTARTS AGE
my-nginx-8474f7bd66-z5p7l 1/1 Running 0 7s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.17.0.1 <none> 443/TCP 72m
my-nginx LoadBalancer 172.17.61.214 10.0.0.3 80:32342/TCP 6s
=> LoadBalancer에 10.0.0.3의 EXTERNAL-IP가 할당된 것을 확인할 수 있다.
이제부터 도메인에 "http://10.0.0.3" 혹은 "http://10.0.0.10:32342"로 접근 시 nginx 화면이 출력되는지 확인한다.
=> 또한 클러스터 외부에서 명령어를 통해서도 접근할 수 있다.
(다른 프롬프트) curl http://10.0.0.3 또는 curl http://10.0.0.10:32342


7. 다른 디플로이먼트를 추가로 생성해도 동일하게 노출시킬 수 있다.
ExternalName 타입의 서비스
: 파드에서 쿠버네티스 클러스터 외부의 엔드포인트에 접속하기 위한 이름을 해결해 주는 역할

- externalName에는 IP 주소를 사용할 수 없다.
1. 임시 파드를 생성
- 임시 파드 생성 하고 포탈 사이트 조회(http://google.com)
> kubectl run -it --rm busybox --image=busybox /bin/sh
vagrant@controlplane:~$ kubectl run -it --rm busybox --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # => 임시 파드 진입 확인
- 포탈 사이트 조회
> wget http://google.com
/ # wget http://google.com
Connecting to google.com (142.250.76.142:80)
Connecting to www.google.com (142.250.206.196:80)
saving to 'index.html'
index.html 100% |*******************************************************| 23624 0:00:00 ETA
'index.html' saved
2. ExternalName 타입의 서비스를 정의
- /home/vagrant/ 에 service-external.yaml 생성
apiVersion: v1
kind: Service
metadata:
name: service-external
spec:
type: ExternalName
externalName: ec2-43-200-255-1.ap-northeast-2.compute.amazonaws.com
=> externalName의 주소에는 IP 주소를 사용할 수 없다!
3. 서비스 생성 후 임시 파드에서 서비스 이름으로 접근
- 서비스 생성 및 확인
> kubectl apply -f service-external.yaml
vagrant@controlplane:~$ kubectl apply -f service-external.yaml
service/service-external created
> kubectl get service
vagrant@controlplane:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostname-deployment LoadBalancer 172.17.26.144 10.0.0.4 80:30813/TCP 10m
kubernetes ClusterIP 172.17.0.1 <none> 443/TCP 88m
my-nginx LoadBalancer 172.17.61.214 10.0.0.3 80:32342/TCP 15m
service-external ExternalName <none> ec2-43-200-255-1.ap-northeast-2.compute.amazonaws.com <none> 4s
- 임시 파드 생성 후 서비스 이름으로 접근
> kubectl run -it --rm busybox --image=busybox /bin/sh
vagrant@controlplane:~$ kubectl run -it --rm busybox --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ #
> wget -q -O - http://service-external
/ # wget -q -O - http://service-external
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
Commercial support is available at
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
- 리소스 정리
> kubectl delete deploy,service --all
인그레스 (ingress)
: "외부 요청에 라우팅 기능 수행 / 가상 호스트 기반의 요청 처리 / SSL&TLS 보안 연결 처리" 를 수행할 수 있다.

- 인그레스 없이 클러스터에 접근하려고 한다면, 앱(서비스) 마다 endpoint가 나눠져 있어
외부에서 접근할 때마다 개별적으로 접근해야 하기 때문에 불편함이 발생한다.
- 인그레스 컨트롤러를 사용하여 접근이 발생하게 되면,
endpoint가 하나로 설정되어 있어 특정 조건에 맞춰 앱(서비스)를 라우팅해주는 역할을 한다.

인그레스를 사용하지 않고 디플로이먼트와 서비스 생성하여 접근
1. 3개의 파드를 실행하는 webserver1과 webserver2 디플로이먼트와 서비스 생성
- /home/vagrant/ 에 webserver1.yaml과 webserver2.yaml 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: webserver1
spec:
replicas: 3
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- name: web1
image: alicek106/rr-test:echo-hostname
ports:
- containerPort: 80
=> webserver2.yaml은 pod의 이름과 label만 바꿔서 동일하게 작성한다.
- 각 디플로이먼트에 사용할 서비스(service1.yaml과 service2.yaml)를 /home/vagrant/ 에 생성
apiVersion: v1
kind: Service
metadata:
name: service1
spec:
type: ClusterIP
selector:
app: web1
ports:
- name: service-port
port: 8080
targetPort: 80
=> service2.yaml은 service의 이름과 label만 바꿔서 동일하게 작성한다.
- 생성한 디플로이먼트와 서비스를 기동 및 확인
> kubectl apply -f webserver1.yaml
vagrant@controlplane:~$ kubectl apply -f webserver1.yml
deployment.apps/webserver1 created
> kubectl apply -f webserver2.yaml
vagrant@controlplane:~$ kubectl apply -f webserver2.yml
deployment.apps/webserver2 created
> kubectl apply -f service1.yaml
vagrant@controlplane:~$ kubectl apply -f service1.yml
service/service1 created
> kubectl apply -f service2.yaml
vagrant@controlplane:~$ kubectl apply -f service2.yml
service/service2 created
> kubectl get pod -o wide
vagrant@controlplane:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED READINESS
NODE GATES
webserver1-59847679c7-26lbq 1/1 Running 0 36s 172.16.196.187 node01 <none> <none>
webserver1-59847679c7-h8fwc 1/1 Running 0 36s 172.16.196.188 node01 <none> <none>
webserver1-59847679c7-rvw4l 1/1 Running 0 36s 172.16.140.115 node02 <none> <none>
webserver2-5789b5989f-6mvvv 1/1 Running 0 32s 172.16.140.116 node02 <none> <none>
webserver2-5789b5989f-gf94h 1/1 Running 0 32s 172.16.196.189 node01 <none> <none>
webserver2-5789b5989f-vln5d 1/1 Running 0 32s 172.16.196.190 node01 <none> <none>
> kubectl get service
vagrant@controlplane:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.17.0.1 <none> 443/TCP 8m9s
service1 ClusterIP 172.17.8.125 <none> 8080/TCP 49s
service2 ClusterIP 172.17.57.119 <none> 9090/TCP 46s
2. CLUSTER-IP 주소와 ClusterIP 서비스의 포트번호로 요청을 전달
=> webserver1과 webserver2를 사용하기 위해서는 각각의 IP와 PORT를 따로 확인해서 입력해야 한다.
결론적으로 매우 귀찮다.
> curl 172.17.8.125:8080 --silent | grep Hello
vagrant@controlplane:~$ curl 172.17.8.125:8080 --silent | grep Hello
<p>Hello, webserver1-59847679c7-h8fwc</p> </blockquote>
> curl 172.17.57.119:9090 --silent | grep Hello
vagrant@controlplane:~$ curl 172.17.57.119:9090 --silent | grep Hello
<p>Hello, webserver2-5789b5989f-6mvvv</p> </blockquote>
인그레스를 생성하여 접근
1. 인그레스 생성
- /home/vagrant/ 에 ingress.yaml 파일 생성 및 등록
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: www.test.com
http:
paths:
- pathType: Prefix
path: /myservice
backend:
service:
name: service1
port:
number: 8080
- pathType: Prefix
path: /yourservice
backend:
service:
name: service2
port:
number: 9090
> kubectl apply -f ingress.yaml
vagrant@controlplane:~$ kubectl apply -f ingress.yaml
Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead
ingress.networking.k8s.io/web-ingress created
> kubectl get ingress
vagrant@controlplane:~$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
web-ingress <none> www.test.com 80 30s
=> 인그레스는 단지 요청을 처리하는 규칙을 정의하는 선언적인 오브젝트이다.
인그레스 컨트롤러 (Ingress Controller)라고 하는 특수한 서버에 적용해야만 규칙을 사용할 수 있다.
2. Nginx 인그레스 컨트롤러 설치
https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters
* 현재 온프레미스 환경에서 사용하고 있기 때문에 클러스터 환경이 설치되어 있어야 컨트롤러의 설치가 가능하다.
- Bare metal clusters를 설치

> kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/baremetal/deploy.yaml
vagrant@controlplane:~$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/baremetal/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
- 클러스터를 설치하며 만들어진 ingress-nginx 내부의 bare metal 클러스터 정보를 조회
> kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-9qb85 0/1 Completed 0 2m53s
pod/ingress-nginx-admission-patch-pq6xs 0/1 Completed 2 2m53s
pod/ingress-nginx-controller-6484d48959-xsmk7 1/1 Running 0 2m53s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 172.17.27.32 <none> 80:31316/TCP,443:32340/TCP 2m54s
service/ingress-nginx-controller-admission ClusterIP 172.17.4.12 <none> 443/TCP 2m54s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 2m53s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-6484d48959 1 1 1 2m53s
NAME STATUS COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create Complete 1/1 19s 2m53s
job.batch/ingress-nginx-admission-patch Complete 1/1 28s 2m53s
- 서비스 확인
> kubectl get service -n ingress-nginx
vagrant@controlplane:~$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 172.17.27.32 <none> 80:31316/TCP,443:32340/TCP 3m39s
ingress-nginx-controller-admission ClusterIP 172.17.4.12 <none> 443/TCP 3m39s
3. hosts 파일에 IP와 www.test.com 을 등록
> sudo vi /etc/hosts 입력 후 a(편집 모드) -> 내용 입력 -> ESC (명령 모드로 전환) -> :wq (저장 후 종료)
vagrant@controlplane:~$ sudo vi /etc/hosts
10.0.0.10 www.test.com
10.0.0.11 www.test.com
10.0.0.12 www.test.com
4. 인그레스 컨트롤러 테스트 진행
- nginx 포트 확인
> kubectl get service
vagrant@controlplane:~$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 172.17.27.32 <none> 80:31316/TCP,443:32340/TCP 10m
ingress-nginx-controller-admission ClusterIP 172.17.4.12 <none> 443/TCP 10m
- 요청
1) www.test.com/myservice로 요청 => service1 에 묶여 있는 파드가 응답한다.
> curl www.test.com:31316/myservice --silent | grep Hello
vagrant@controlplane:~$ curl http://www.test.com:31316/myservice --silent | grep Hello
<p>Hello, webserver1-59847679c7-h8fwc</p> </blockquote>
2) www.test.com/yourservice로 요청 => service2 에 묶여 있는 파드가 응답한다.
> curl www.test.com:31316/yourservice -- silent | grep Hello
vagrant@controlplane:~$ curl http://www.test.com:31316/yourservice --silent | grep Hello
<p>Hello, webserver2-5789b5989f-gf94h</p> </blockquote>
=> 위 요청은 http://www.test.com:31316/myservice 로 요청이 올 경우 http://172.17.8.125:8080/ 으로 보내고,
http://www.test.com:31316/yourservice 로 요청이 올 경우 http://172.17.57.119:9090/ 으로 보낸다.
5. ingress-nginx-controlloer 의 타입을 NodePort -> LoadBalancer 타입으로 변경
- 네임스페이스 ingress-nginx의 서비스 정보를 확인하면 NodePort 타입인 것을 확인할 수 있다.
> kubectl get service -n ingress-nginx
vagrant@controlplane:~$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 172.17.27.32 <none> 80:31316/TCP,443:32340/TCP 17m
ingress-nginx-controller-admission ClusterIP 172.17.4.12 <none> 443/TCP 17m
- edit 모드를 사용하여 ingress-nginx-controller 의 type을 NodePort -> LoadBalancer로 변경
> kubectl edit service ingress-nginx-controller -n ingress-nginx
=> 네임스페이스 ingress-nginx 내부의 서비스 ingress-nginx-controller 의 정보를 수정하는 명령어
vagrant@controlplane:~$ kubectl edit service ingress-nginx-controller -n ingress-nginx
:
:
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
sessionAffinity: None
type: LoadBalancer ⇐ NodePort를 LoadBalancer로 변경
status:
loadBalancer: {}
- 서비스 타입의 변경을 확인
> kubectl get service -n ingress-nginx
vagrant@controlplane:~$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 172.17.27.32 10.0.0.3 80:31316/TCP,443:32340/TCP 20m
ingress-nginx-controller-admission ClusterIP 172.17.4.12 <none> 443/TCP 20m
'Study > seSAC 금천 4기' 카테고리의 다른 글
| 클라우드_2일차_241002 (0) | 2024.10.10 |
|---|---|
| 클라우드_1일차_241001 (0) | 2024.10.08 |
| 컨테이너 Orchestration_2일차_240925 (0) | 2024.09.30 |
| 컨테이너 Orchestration_1일차_240924 (0) | 2024.09.30 |
| 컨테이터 애플리케이션 개발_4일차_240923 (0) | 2024.09.30 |