서비스(Service) : 포드를 연결하고 외부에 노출
- 사용자들이 포드들의 내부에 접근하기 위해 생성하는 오브젝트
- 쿠버네티스 리소스를 생성하는 yaml 파일에 containerPort 항목에 개방할 포트를 정하지만 바로 외부로 노출되는 것은 아님. 외부로 노출시키기 위해서는 서비스를 꼭 생성해야함
핵심 기능
- 여러 개의 포드에 쉽게 접근할 수 있도록 고유한 도메인 이름을 부여
- 여러 개의 포드에 접근할 때, 요청을 분산하는 로드 밸런서 기능을 수행
- 클라우드 플랫폼의 로드 밸런서, 클러스터 노드의 포트 등을 통해 포드를 외부로 노출
서비스의 타입
- ClusterIP
- 쿠버네티스 네부에서만 포드들에 접근할 때 사용
- 외부로 노출시키지 않기 때문에 내부에서만 작동되는 포드들에 적용
- NodePort
- 포드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개방
- 외부에서 접근이 가능해지는 서비스 타입
- 접근 포트는 랜덤으로 정해지지만 특정 포트로 접근하도록 설정 가능
- LoadBalancer
- 클라우드 플랫폼에서 제공하는 로드밸런서를 동적으로 프로비저닝해서 포드에 연결
- NodePort와 마찬가지로 외부에서 접근이 가능해지는 서비스 타입
- 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 사용 가능
ClusterIP
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-clusterip
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: ClusterIP
- spec.selector
- 서비스에서 어떤 라벨을 가지는 포드에 접근할 수 있게 만들 것인지 결정
- sepc.ports.port
- 쿠버네티스 내부에서만 사용할 수 있는 고유한 IP(ClusterIP)를 할당받음
- port 항목에는 서비스의 IP에 접근할 때 사용할 포트를 설정
- spec.ports.targetPort
- selector 항목에서 정의한 라벨에 의해 접근 대상이 된 파드들이 내부적으로 사용하고 있는 포트 명시
- spec.type
- 서비스의 타입을 명시
- 생성 및 확인
- curl이 존재하는 우분투 이미지 생성 후 좀 전에 생성한 ClusterIP의 개방포트(8080)로 요청
- 여러번 요청을 보내보면 별도의 설정을 하지 않았음에도 서비스는 연결된 포드에 대해 로드 밸런싱을 수행하는 것을 볼 수 있음.
- IP 뿐만 아니라 서비스 이름 그 자체로도 접근이 가능
- 쿠버네티스가 내부 DNS를 구동하고 있기 때문에 가능
- 실제로 여러 포드가 클러스터 내부에서 서로를 찾아 연결할 때에는 서비스의 이름과 같은 도메인 이름을 사용하는 것이 일반적
- 서비스의 라벨 셀렉터와 포드의 라벨이 매칭돼 연결되면 쿠버네티스는 자동으로 엔드포인트라고 부르는 오브젝트를 별도로 생성
- 엔드포인트 또한 오브젝트이기에 이론상으로 서비스와 엔드포인트를 따로 만드는 것이 가능
- 삭제 : kubectl delete svc hostname-svc-clusterip
NodePort
# hostname-svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: NodePort
- ClusterIP 만들때와 같고 마지막에 type만 다름
- 생성 후 개방된 포트로 접근해보기
- kubectl apply -f hostname-svc-nodeport.yaml
- 개방된 32565 포트는 모든 노드에서 접근할 수 있는 포트를 의미
- 단, GKE에서 쿠버네티스를 사용하고 있는 경우, 각 노드에 랜덤한 포트에 접근하기 위해 별도로 방화벽을 설정해야함
- AWS에서도 마찬가지로 Security Group에 별도의 Inbound 규칙을 추가하지 않으면 NodePort 통신이 실패할 수도 있음
$gcloud compute firewall-rules create temp-nodeport-svc --allow=tcp:32565 # 추가
$gcloud compute firewall-rules delete temp-nodeport-svc # 삭제
- 각 노드에서 개방되는 포트는 기본적으로 30000~32768 포트 중에 랜덤으로 선택되지만, YAML 파일에 nodePort 항목을 정의하면 원하는 포트 선택 가능
...
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
nodePort: 31000
...
- NodePort 타입의 서비스를 만든 것을 보면 하나 이상한 점이 있음, 바로 ClusterIP가 할당 된것
- 실제로 ClusterIP에 접근했던 것처럼 curl을 이용해 접근해보면 접근 가능
- 사실 NodePort가 ClusterIP 기능을 포함하고 있기 때문
- NodePort 타입의 서비스를 생성하면 자동으로 ClusterIP 기능을 사용할 수 있기 때문에 쿠버네티스 클러스터에서 서비스의 내부 IP와 DNS 이름을 사용해 접근이 가능한 것
- 그러므로 NodePort 타입의 서비스는 내부, 외부 모두 접근이 가능
- 기본적으로 NodePort가 사용 가능한 포트 범위는 30000~32768 이지만, API 서버 컴포넌트의 실행 옵션을 변경하면 원하는 포트 범위로 설정 가능
- —service-node-port-range=30000-35000
- 특정 클라이언트가 같은 포드로부터만 처리되게 하려면 서비스의 YAML 파일에서
- sessionAffinity 항목을 ClientIP로 설정
...
spec:
sessionAffinity: ClientIP
...
- 실제 운영 환경에서 NodePort 서비스를 외부에 제공하는 경우는 많지 않음
- 포트 번호를 80, 443으로 설정하기에 적합하지 않은 경우도 많고 SSL 인증서 적용, 라우팅 등과 같은 복잡한 설정을 서비스에 적용하기가 어렵기 때문
- Ingress 라고 부르는 쿠버네티스 오브젝트에서 간접적으로 사용되는 경우가 많음
- 지금은 “외부 요청을 실제로 받아들이는 관문” 정도로 알면 됨
- LoadBalancer와 NodePort를 합치면 Ingress 오브젝트를 사용 가능
LoadBalancer
- 서비스의 생성과 동시에 로드 밸런서를 새롭게 생성해 포드와 연결
- NodePort를 사용할 때는 각 노드의 IP를 알아야만 포드에 접근할 수 있었찌만, 로드밸런서의 경우 클라우드 플랫폼으로 부터 도메인 이름과 IP를 할당받기 때문에 더욱 쉽게 포드에 접근 가능
- 단, 로드밸런서의 경우 로드 밸런서를 동적으로 생성하는 기능을 제공하는 환경에서만 사용할 수 있음
- 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 로드밸런서를 사용 가능하며 가상머신이나 온프레미스 환경에서는 사용하기 어려울 수 있음 (MetalLB, 오픈스택의 LBaaS 등과 같이 온프레미스에서도 가능하게 하는 방법들이 존재하긴 함)
# hostname-svc-lb.yaml
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-lb
spec:
ports:
- name: web-port
port: 80
targetPort: 80
selector:
app: webserver
type: LoadBalancer
- kubectl apply -f hostname-svc-lb.yaml
- 현재 본인은 로컬에 Docker for Windows의 Kubetnetes를 사용중이어서 EXTERNAL-IP가 localhost로 표시됨.
- AWS를 사용할 경우 a34kjsf….elb.amazonaws.com 라는 도메인으로 뜰것임
- 뜨기는 뜨지만 로드밸런싱은 안되고 계속 저 pod만 연결됨
- 아님; 재차 확인 결과 pending이 뜨는것이 정상 어케한거지 ;
- localhost 또한 접근 안됨.
- EXTERNAL-IP 외에 PORT를 확인해보면 80 : 32718가 존재하는데 이는 마치 NodePort의 타입과 비슷해보임
- 포트를 개방한 이유는 로드밸런서 서비스가 포드로 요청을 전송하는 원리에 있음
- LoadBalancer 타입의 서비스가 생성됨과 동시에 모든 워커 노드는 포드에 접근할 수 있느 랜덤한 포트를 개방 (ex> 32718)
- 클라우드 플랫폼에서 생성된 로드 밸런서로 요청이 들어오면 이 요청은 쿠버네티스의 워커 노드 중 하나로 전달되며, 이때 사용되는 포트는 1번에서 개방한 포트를 사용
- 워커 노드로 전달된 요청은 포드 중 하나로 전달되어 처리됨
- 로드밸런서 타입으로 생성했지만, NodePort의 간접적인 기능 또한 자동으로 사용할 수 있는 셈
- 또한, 클라우드 로드밸런서의 유형을 바꿔서 생성할 수도 있음
...
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-lb
**annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"**
spec:
ports:
- name: web-port
port: 80
targetPort: 80
selector:
...
- annotation은 라벨처럼 해당 리소스의 추가적인 정보를 나타내기 위한 키:값 쌍으로 이루어짐
- 특정 용도로 사용되도록 쿠버네티스에 미리 정의된 몇 가지 주석이 존재하며 리소스에 특별한 설정값을 부여하기 위해 사용됨
- 삭제
- kubectl delete -f hostname-svc-lb.yaml
트래픽의 분배를 결정하기
externalTrafficPolicy : 트래픽 처리를 Local인지 Cluster인지 결정
- 로드밸런서 타입의 서비스를 사용하게 되면 외부에서 들어온 요청은 각 노드 중 하나로 보내지며, 그 노드에서 다시 포드로 접근하게 됨
- 하지만, 이러한 요청이 꼭 효율적이다 라는 보장은 없음
A로 요청이 들어왔지만 로드밸런서에 의해 B로 전송되는 모습
- B로 전달하게 되면 불필요한 네트워크 홉(hob)이 한 단계 발생되고 노드 간의 리다이렉트가 발생하게 되어 트래픽의 출발지 주소가 바뀌는 SNAT이 발생하고, 이로 인해 클라이언트의 IP 주소 또한 보존되지 않음
- A로 들어온 요청을 굳이 B로 전달하지 않고 A 노드에서 처리할 수는 없을까 ?
- externalTrafficPolicy를 설정해서 바꿀 수있음.
- kubectl get -o yaml 명령어를 통해 서비스의 모든 속성을 출력해 볼 수 있음.
- kubectl get svc hostnamesvc-nodeport -o yaml
# kubectl get svc hostnamesvc-nodeport -o yaml
apiVersion: v1
kind: Service
metadata:
annotaions:
...
**externalTrafficPolicy: Cluster**
...
- 이를 클러스터가 아니라 Local로 설정하게 되면 포드가 생성된 노드에서만 포드로 접근이 가능해지며 로컬 노드에 위치한 포드 중 하나로 요청이 전달됨
- 추가적인 네트워크 홉이 발생하지 않으며, 전달되는 요청의 클라이언트 IP 또한 보존이 됨
ExternalName : 요청을 외부로 리다이렉트를하는 서비스
- 쿠버네티스를 외부 시스템과 연동해야 할 때가 생길 수도 있음
- 서비스가 외부 도메인을 가르키도록 설정하는 방법
apiVersion: v1
kind: Service
metadata:
name: externalname-svc
spec:
type: ExternalName
externalName: my.database.com
- 리소스 정리
- kubectl delete -f ./
온프레미스 환경에서 LoadBalancer 타입의 서비스 사용하기
MetalLB 설치
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
- kube-system의 kube-proxy 설정 변경하기
- kubectl edit configmap -n kube-system kube-proxy
- 변경하는 이유 : 쿠버네티스 1.14.2 버전부터 kube-proxy IPVS mode를 사용하려면 strictARP모드를 켜줘야 함. 기본적으로 strictARP를 활성화 하기 때문에 kube-router를 서비스 프록시로 사용하는 경우에는 필요하지 않음.
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
수정전
수정후
- 구성을 kubeadm-config에 추가하는 법
# **see what changes** would be made, returns nonzero returncode if different
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl diff -f - -n kube-system
# actually **apply** the changes, returns nonzero returncode on errors only
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
- 매니페스트 적용을 통한 MetalLB 설치
# namespace 만들기
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
# 구성요소 설치
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
- metallb-system 네임스페이스 아래의 클러스터에 MetalLB가 배포됨
- 매니페스트 구성요소
- metallb-system/controller 배포 : IP 주소 할당을 처리하는 클러스터 전체 컨트롤러
- metallb-system/speaker 데몬셋 : 서비스에 도달할 수 있도록 내가 선택한 프로토콜을 알려주는 컴포넌트
- 서비스 계정 : 구성 요소가 작동하는데 필요한 RBAC 권한과 컨트롤러와 스피커에 대한 계정
- 설치 매니페스트에는 구성파일이 포함되어 있지 않음
# Secret 생성
# error: failed to create secret secrets "memberlist" already exists
# kubectl get secret -n metallb-system (확인결과 기본적으로 생성되는거 같음)
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
# 라우팅 처리를 위한 configmap 생성
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 10.1.0.2-10.1.0.100
- 생성 후 아까 생성한 LB를 확인해보면 EXTERNAL-IP가 연결됨
- IPv4 주소나 localhost로 접근해보면 로드 밸런싱 해서 보여주는걸 확인 가능
'Infra > Kubernetes' 카테고리의 다른 글
Kubernetes Deployment (쿠버네티스 디플로이먼트) (0) | 2022.08.30 |
---|---|
Kubernetes Pod (쿠버네티스 팟) (0) | 2022.08.30 |