서비스 네트워킹
Deployment를 통해 생성된 파드의 IP를 통해서 직접 접근할 수도 있지만, 파드가 재생성될 경우 경우 IP가 영속적이지 않기 때문에 변경될 수 있다는 점을 유의해야 한다. 여러 개의 Deployment를 하나의 완벽한 애플리케이션으로 연동하려면 파드 IP가 아닌 서로를 발견할 수 있는 방법이 필요하다.
서비스는 여러 개의 팟에 쉽게 접근할 수 있도록 도메인 이름을 부여하고, 로드 밸런서 기능을 수행하여 파드를 외부로 노출시켜준다.
서비스는 Cluster IP, NodePort, LoadBalancer 이렇게 3가지 타입이 있다.
먼저 ClusterIP의 대한 얘기 해보겠다.
예시:
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-clusterip
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostname-deployment
spec:
replicas: 3
selector:
matchLabels:
app: webserver
template:
metadata:
name: my-webserver
labels:
app: webserver
spec:
containers:
- name: my-webserver
image: waji97/test:v1
ports:
- containerPort: 80
생성된 서비스는 쿠버네티스 내부에서만 사용할 수 있는 고유 IP(Cluster IP)를 할당 받는데, 6번 줄에 있는 ports:
는 해당 IP의 어떤 포트를 사용해서 접근 가능한지 기입한다. 똑같은 필드에 있는 targetPort
는 접근할 파드가 사용하고 있는 포트 번호를 나타낸다. 10번 줄에 있는 selector
는 이 서비스에서 어떤 라벨을 가지는 파드에 접근할 수 있게 만들 것인지를 나타낸다. 이렇게 설정을 하면, 내부적으로 파드의 IP가 변경되어도 서비스를 통해 접근하게 되므로 상관없어질 것이다. Cluster IP는 외부에서 접근할 수가 없다.
이번에는 NodePort 타입이다
예시:
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: NodePort
Manifest파일 형태는 거의 동일 하지만 마지막에 type:
필드만 NodePort로 바뀐다. Cluster IP 타입일 때에는 단순히 파드에 연결해주는 것이었다. NodePort는 외부에서 어떤 노드든 간에 해당 노드의 IP에 접근하고 NodePort의 포트번호로 접근하기만 하면 해당 파드로 연결을 해준다. 포트는 30000 ~ 32767 중 랜덤으로 지정된다.
마지막에 있는 LoadBalancer 타입은 노드포트에 접근하게끔 로드밸런싱을 해주는 타입인데 클라우드 플랫폼 환경에서 주로 사용가능 하다. 예를 들어 AWS 클라우드 플랫폼에서 로드 밸런서 서비스를 지정 해주면, AWS상 로드밸런서가 자동 생성 된고 로드 밸런서 역할을 수행 한다(AWS EKS 클러스터가 설정 되어 있는 과정에서만). 그 외 Baremetal 환경에서는 오픈소스 Load Balancer인 MetalLB를 사용하여 쿠버네티스 클러스터에 Load Balancer를 별도로 구축 가능 하다. MetalLB는 간단하게 로드 밸런서 기능을 해주는 파드를 생성 해준다.
MetalLB에 대한 기본 정보-
- MetalLB는 L2모드와 BGP모드를 지원 한다
- BGP 모드는 실제 L3스위치 아니면 라우터를 사용하여 로드 밸런싱 기능을 사용 할 수 있다. 외부에서 라우터의 IP로 접속하면 실제 서비스로 연결 시켜준 되, 서비스가 파드로 연결 시켜준다.
- L2 모드는 클러스터 내부 전체 노드에 DaemonSet Controller를 이용하여 Speaker Pod를 구성하는 방식을 사용한다.
- Speaker Pod 중 Master를 선출하여 선출 된 Master에서 External-IP(외부 연결이 가능한 IP)를 관리한다.
- L2 모드는 Master Speaker에서 MetalLB 정보를 다른 Member Speaker Pod에 전달하기위해 ARP(Address Resolution Protocol)를 사용한다.
- MetalLB L2모드를 사용하기 위해서는 kube-proxy Pod에서 ARP 사용 허가를 해주어야 한다.
- 쿠버네티스 클러스터 내부의 모든 kube-proxy Pod에서 ARP 사용 허가를 해주어야 한다.
기본적인 MetalLB의 동작 흐름:
- NodePort가 speaker파드로 연결되고, speaker 파드들은 controller로 연결 된다.
- 외부에서 이 로드 밸런서의 IP로 접속하게 되면, 어느 노드든 상관 없이 speaker를 통해 controller로 연결되고, controller는 다시 NodePort로 분배해 준다.
- 그리고 NodePort가 내부의 실제 서비스로 다시 연결 해 준다.
- 최종적으로 이 서비스가 다시 파드로 연결 시켜준다.
BGP모드는 Border Gateway Protocol의 약자로 인터넷에서 라우팅 정보를 교환하고 관리하기 위해 사용 된다
ARP는 IP 주소와 MAC 주소 간의 매핑을 수행하는 네트워크 프로토콜이다
예시:
vi app.yaml
# 로드 밸런서 YAML 파일
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
ports:
- name: web-port
port: 80
targetPort: 8080
selector:
app: webserver
type: LoadBalancer
---
# 웹 사이트 배포 YAML 파일
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 8080
이렇게 YAML 파일을 적용 시킨 후 결과를 확인 하면
# YAML 파일 적용
kubectl apply -f app.yaml
# 모든 리소스 확인
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-6f67db9747-l8shl 1/1 Running 0 6s
pod/nginx-deployment-6f67db9747-tcc8k 1/1 Running 0 6s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 24h
service/nginx-loadbalancer LoadBalancer 10.233.8.88 <pending> 80:31810/TCP 6s
현재 VM을 사용 하여 예시를 사용 하였기 때문에 로드 밸런서가 실제로 생성 되지 않는다. 그렇기 떄문에 EXTERNAL-IP도 아직 <pending> 상태이고 on-premise 환경에서 사용되는 로드 밸런서인 MetalLB를 사용 해야 한다. MetalLB를 설치 하는 방식은 Helm 차트, 매니페스트 파일 그리고 Kubespray로 통해 할 수 있다.
참고용 MetalLB installation 페이지 링크: https://metallb.universe.tf/installation/
공식 사이트에 나와있는 매니페스트 파일 방식으로 L2모드 설치를 진행 해 보았다. L2 모드는 대부분의 경우, 프로토콜 특정 구성이 필요하지 않으며, IP 주소만 필요하고 쉽게 구성 할 수 있다.
L2 모드는 워커 노드의 네트워크 인터페이스의 IP를 할당할 필요가 없다. 이 모드는 로컬 네트워크에서 ARP 요청에 직접 응답하여 클라이언트에게 기계의 MAC 주소를 제공 하는 모드다.
제일 먼저, strictARP 모드를 활성화 해야 한다.
마스터 노드에서,
kubectl edit configmap -n kube-system kube-proxy
vim editor 처럼 파일 수정이 가능 하다. 파일 속에서 41번째 줄에 있는 값을 변경 해준다.
# 기본으로 false
strictARP: true
그 후 저장 후 파일에서 나온다. MetalLB설치 할 준비는 끝났으나 이제 바로 매니페스트 파일을 적용 시켜 주면 된다
# 공식 사이트 Installation에 나온 링크
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
namespace/metallb-system configured
customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
serviceaccount/controller unchanged
serviceaccount/speaker unchanged
role.rbac.authorization.k8s.io/controller configured
role.rbac.authorization.k8s.io/pod-lister configured
clusterrole.rbac.authorization.k8s.io/metallb-system:controller configured
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker configured
rolebinding.rbac.authorization.k8s.io/controller configured
rolebinding.rbac.authorization.k8s.io/pod-lister configured
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller unchanged
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker unchanged
configmap/metallb-excludel2 created
secret/webhook-server-cert created
service/webhook-service created
deployment.apps/controller configured
daemonset.apps/speaker configured
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
이렇게 매니페스트를 적용 하게 되면 자동으로 MetalLB의 모든 필요 요소들이 자동으로 설치가 된다.
확인을 하기 위해 metallb-system namespace을 보면, controller과 speaker들이 보일 것이다
# 확인 하기 위해 새로 생성 된 metallb 네임 스페이스 리소스들 보기
kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/controller-5fd797fbf7-r28s6 0/1 Running 0 17s
pod/controller-bdf98b979-pp7dp 1/1 Running 0 80s
pod/speaker-2hx68 1/1 Running 0 80s
pod/speaker-p2nh4 1/1 Running 0 80s
pod/speaker-r95cx 0/1 Running 0 17s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/webhook-service ClusterIP 10.233.32.213 <none> 443/TCP 17s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/speaker 3 3 2 1 2 kubernetes.io/os=linux 80s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 80s
초기 설치는 끝났으나 바로 사용 가능 하지는 않다. 사용하기 위해 먼저 초기 설정을 해 줘야 한다.
참고용 MetalLB Configuration 링크: https://metallb.universe.tf/configuration/
먼저 IP 풀을 지정 해 줘야 한다.
# IP 풀 설정을 위해 매니페스트 파일 생성
vi metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.40-192.168.1.50 # IP 주소 풀 할당
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: metal
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
매니페스트 파일 저장 후 적용을 한다
kubectl apply -f metallb-config.yaml
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/metal created
테스팅을 위해 이미 배포 되어 있는 웹 사이트의 서비스 타입을 LoadBalancer로 바꿔 보았다
# 웹 사이트 매니페스트 파일
vi my-app.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: LoadBalancer # 전에는 NodePort로 서비스
selector:
app: my-app
ports:
- protocol: TCP
port: 80
진행 중인 서비스들 목록을 확인 해보면 이젠 로드 밸런서가 EXTERNAL-IP를 지정 한 IP 풀 안에서 자동으로 부여 하는 것을 확인 할 수 있다
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 27h
my-app-service LoadBalancer 10.233.11.219 192.168.1.40 80:30208/TCP 25m
본 IP로 들어가서 확인 하면