
쿠버네티스에서 배포한 Pod를 외부에서 접근하기 위해서는 여러 가지 방법들이 존재한다.
그중 가장 쉬운 방법은 Pod와 연결된 Service를 생성하고 Type을 NodePort
로 설정하여 접속하는 것이다.
하지만 해당 방법은 노드를 통해 Pod에 접속하는 것이기 때문에 클라이언트가 노드의 IP, Port를 모두 알고 있어야만 접속이 가능하다. 때문에 편의성도 떨어지고 보안적으로도 좋지 못한 방법이라 주로 개발/테스트 환경에서만 사용한다.
실제 운영환경에서는 이러한 문제점들을 해결하기 위해 Ingress라는 리소스를 활용한다.
Ingress 란?
아래는 Ingress에 대한 Kubernetes 공식문서의 내용이다.
요약해 보자면 Ingress는 쿠버네티스에 배포한 웹 서비스에 대해 개별적인 라우팅 규칙을 적용할 수 있으며 이를 활용하여 외부에서 접속할 수 있도록 리버스 프록시와 유사한 역할을 하는 리소스이다.
아래는 NodePort와 비교했을 때 Ingress를 활용하면 어떤 장점이 있는지 정리해 보았다.
- 노드에 직접 트래픽을 요청하지 않기 때문에 보안성이 좋다.
- 접속할 때
IP:Port
대신 도메인을 적용할 수 있어 클라이언트 입장에서 편의성이 좋다. - URL Path 별로 다른 서비스로 라우팅 하는 등 다양한 라우팅 규칙을 활용할 수 있다.
- LoadBalancer와 연계하여 접속 트래픽을 부하분산 시킬 수 있다
- Secret을 활용하여 간단하게 SSL/TLS 설정이 가능하다.
이러한 이유 때문에 실제 운영환경에서는 Ingress를 통한 웹 트래픽 제어를 많이 활용한다.
하지만 Ingress를 사용하기 위해서는 해당 기능을 제공하는 Ingress Controller를 같이 설치하여 사용해야 한다.
Ingress Controller는 다양한 종류가 있는데 온프레미스의 경우 Nginx Ingress, Traefik 등이 많이 사용되고 AWS 같은 클라우드 플랫폼에서는 본인들의 LoadBalancer 리소스와 연동할 수 있는 ALB Ingress Controller 같은 서비스가 있다.
이외에 다른 컨트롤러에 대한 지원 내용은 여기를 참고한다.
해당 글에서는 클라우드 환경을 사용하지 않고 있으므로 Nginx Ingress Controller를 활용하여 진행한다.
MetalLB 설치하기
Nginx Ingress를 사용하기 앞서 Controller 서비스를 LoadBalancer 타입으로 배포하기 위해 MetalLB라는 것을 설치해야 한다.
MetalLB는 온프레미스 쿠버네티스에서도 LoadBalancer 리소스를 사용할 수 있도록 도와주는 서비스이다.
실제 LoadBalancer를 생성하는 클라우드 환경과 다르게 MetalLB는 Speaker
라는 Daemonset을 통해 LoadBalancer에 설정된 External IP를 전파한다. 전파에는 ARP(IPv4)/NDP(IPv6)
, BGP
표준 프로토콜을 활용한다.
동작할 때는 Layer2
, BGP
2가지 모드를 설정할 수 있는데 내용은 아래와 같다.
- Layer2 : 배포된 Speaker Pod 중 1개를 리더로 선출하고 모든 트래픽을 리더 Pod가 수신 한 다음에 알맞은 Pod로 분산시킨다. 만약 리더 Pod에 장애가 발생 시 다른 Speaker Pod 중 리더를 재선출한다.
- BGP : 외부 라우터를 활용하여 Speaker Pod가 보낸 External IP를 관리하고 ECMP를 이용하여 알맞은 Pod로 트래픽을 분산시킨다.
가장 큰 차이점은 트래픽 라우팅에 사용되는 IP테이블 정보를 리더 Speaker
Pod가 있는 단일 노드가 관리할 것인지(Layer2), 아니면 외부 라우터를 활용하여 관리할 것인지(BGP)이다.
주로 소규모 환경에서는 Layer2
를 활용하고 그보다 더 큰 규모일 경우 BGP
를 활용한다고 한다.
이제 설치해 보자.
MetalLB는 Helm, Kustomize, 매니페스트에 대한 설치 방법을 지원하고 있으며 해당 내용에서는 매니페스트를 통해 설치를 진행해 본다.
(자세한 내용은 여기를 참고한다.)
- 기본 설정
IPVS 모드에서 kube-proxy
를 사용하는 경우 Kubernetes v1.14.2부터 엄격한 ARP 모드를 활성화해야 한다.
$ kubectl edit configmap -n kube-system kube-proxy
내용 중 strictARP
값이 false
로 되어있다면 true
로 변경해 준다.
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
- 매니페스트를 통해 MetalLB 설치
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
배포 후에 리소스 목록을 확인하면 metallb-system
이라는 네임스페이스에 controller
와 speaker
Pod가 배포된다.
$ kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/controller-586bfc6b59-pmfpq 1/1 Running 0 78s
pod/speaker-6kcwx 1/1 Running 0 77s
pod/speaker-ghzwc 1/1 Running 0 77s
pod/speaker-lsrs2 1/1 Running 0 77s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/webhook-service ClusterIP 10.97.25.169 <none> 443/TCP 78s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/speaker 3 3 3 3 3 kubernetes.io/os=linux 78s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 78s
NAME DESIRED CURRENT READY AGE
replicaset.apps/controller-586bfc6b59 1 1 1 78s
- External IP 설정을 위한 커스텀 리소스(CRD) 생성
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: address-pools
namespace: metallb-system
spec:
addresses:
- 192.168.45.101/32
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: metallb-network
namespace: metallb-system
spec:
ipAddressPools:
- address-pools
kind는 L2Advertisement
로 생성하여 IP 전파 방식을 Layer2로 설정했고 addresses
의 경우 노드의 IP 대역 중 남는IP를 설정해 주었다.
추가로 L2Advertisement
의 ipAddressPools
이름은 IPAddressPool
리소스의 name과 동일하게 설정해야 한다.
Nginx Ingress Controller 설치하기
Nginx Ingress Controller는 경량화 웹 서비스인 Nginx의 Proxy 기능을 쿠버네티스에서 활용할 수 있도록 제공하는 서비스이다.
DockerHub에서 1,000만 번 이상 다운로드된 만큼 가장 대중적이고 많이 사용하는 Ingress Controller 중 하나이다.
Nginx Ingress Controller는 Helm을 통해 설치한다.
- 네임스페이스 생성
$ kubectl create ns ingress-nginx
- Helm repo 추가
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
- Helm install
$ helm install -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx
배포가 완료되면 아래 리소스들이 생성된다.
$ kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-controller-bfc454775-5wgw9 1/1 Running 0 2m49s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
AGE
service/ingress-nginx-controller LoadBalancer 10.110.100.91 192.168.45.101 80:31823/TCP,443:31774/TCP 2m49s
service/ingress-nginx-controller-admission ClusterIP 10.108.20.119 <none> 443/TCP
2m49s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 2m49s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-bfc454775 1 1 1 2m49s
이 중 ingress-nginx-controller
서비스의 External IP
를 확인해 보면 MetalLB에서 설정해 둔 192.168.45.101
IP를 발급받은 걸 확인할 수 있다.
이제 해당 Controller와 ip를 이용하여 ingress 설정을 진행해 본다.
Ingress를 통해 웹 서비스 접속하기
Nginx 서비스를 배포하고 ingress를 설정하여 외부에서 접속해 본다.
- Nginx Pod 및 Service 배포
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
- Ingress 생성
Nginx Ingress Controller의 IP뒤에 /nginx
라는 path를 붙여서 접속하면 nginx Pod와 연결되도록 설정한다.(Path 기반 라우팅)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /nginx
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
annotation
은 Ingress Controller에서 지원하는 옵션들을 사용할 때 활용하며 어떤 Ingress Controller를 사용하냐에 따라 사용할 수 있는 옵션이 달라진다. 보통 Controller마다 공식문서를 지원하고 있으며 Nginx Ingress Controller의 경우 여기를 참고하면 된다.
위에서 사용한 rewrite-target
옵션은 가장 많이 사용하는 기본 옵션으로 ingress로 접속 시 사용한 주소를 서비스에서는 /
로 사용할 수 있게끔 재지정하는 옵션이다. 만약 path가 여러 개 설정될 경우 서비스는 보통 /
를 기준으로 트래픽을 처리하게끔 개발하기 때문에 해당 옵션을 사용하지 않으면 서비스 접속에 문제가 발생할 수 있다.
- 접속 확인
웹 브라우저를 켜고 Nginx Ingress Controller의 External IP
및 path
를 통해 접속해 본다.
목표한 대로 /nginx
경로를 통해 nginx Pod에 잘 접속되는 것을 볼 수 있다.
- 도메인을 통해 접속하기
이번에는 path
가 아닌 도메인을 지정하여 루트경로로 nginx Pod에 접속해 본다.(Host 기반 라우팅)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: nginx
rules:
- host: nginx-test.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
도메인 접속을 하기 위해 로컬 DNS에 해당 도메인을 Ingress Controller IP와 매칭시킨다.
#C:\Windows\System32\drivers\etc\hosts
192.168.45.101 nginx.test.com
이제 동일한 방법으로 웹 브라우저를 켜고 nginx.test.com
에 접속하여 확인해 보자.
별도의 path
를 입력하지 않고 도메인으로만 잘 접속이 되는 것을 볼 수 있다.
참고자료
Annotations - Ingress-Nginx Controller
Annotations You can add these Kubernetes annotations to specific Ingress objects to customize their behavior. Tip Annotation keys and values can only be strings. Other types, such as boolean or numeric values must be quoted, i.e. "true", "false", "100". Ca
kubernetes.github.io
'Kubernetes' 카테고리의 다른 글
쿠버네티스 대시보드로 클러스터 모니터링하기 (1) | 2024.01.23 |
---|---|
Kubeadm으로 쿠버네티스 설치하기 (0) | 2024.01.14 |
Helm 알아보기 (0) | 2023.12.31 |
쿠버네티스 컨트롤러 알아보기 (0) | 2023.12.17 |
AKS를 사용하여 쿠버네티스 구성하기 (0) | 2023.12.10 |