Skip to main content

Ingress 컨트롤러 & 리소스

인그레스는 외부 요청을 처리하는 방법을 정의하는 오브젝트다. 인그레스는 다양한 기능을 담당한다. 예를 들어, 특정 경로로 들어온 요청을 어떤 서비스로 전달할지 정의하는 라우팅 규칙, 가상 호스트를 기반으로한 요청 처리, SSL/TLS 보안 연결 처리 등을 담당한다.

NodePort나 LoadBalancer를 사용하면 위와 같은 기능을 구현할 수 있지만, NodePort의 개수가 많을 경우 각 서비스에 대해 설정을 별도로 해주어야 하는 번거로움이 있을 수 있다. 하지만 인그레스를 사용하면 한 곳에만 설정을 하면 되기 때문에 편리하다. 인그레스를 통해 요청의 경로와 처리 방식을 중앙에서 관리할 수 있어서 유연성과 효율성을 높일 수 있다. 쉽게 말하면 Ingress를 통해 특정 트래픽을 지정한 서비스 쪽으로 라우팅을 해 줄 수 있다.

image.png


예시:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-example
spec:
  rules:
    - host: example.com
      http:
        paths:
        - pathType: Prefix
          path: /
          backend:
            name: hostname-service       	# 목적지 서비스의 이름과 포트 번호
            port: 80							

여기서 host:는 해당 도메인 이름으로 접근하는 요청에 대해 처리 규칙을 적용 한다는 뜻이다. 그리고 path: 는 해당 경로의 요청을 어떤 서비스로 전달 할 것인지 정의한다. 

인그레스는 요청 처리 규칙을 정의하는 선언적인 오브젝트일 뿐이며, 실제로 외부 요청을 처리하지는 않는다. 인그레스 규칙을 사용하기 위해서는 인그레스 컨트롤러라고 하는 특수한 서버에 적용해야 한다. 인그레스 컨트롤러 서버가 실제로 외부 요청을 받아들이고 인그레스 규칙을 적용한다.


인그레스 설정

클라우드 서비스를 사용하는 경우, 자사의 로드밸런서 서비스와 연동하여 인그레스를 사용할 수 있다. 그러나 자체 클라우드 구축 시에는 보통 Nginx 웹 서버 인그레스 컨트롤러를 사용 한다. 이는 쿠버네티스에서 공식적으로 개발되고 있어서 공식 깃허브 저장소에서 설치를 위한 YAML 파일을 직접 내려받을 수 있다. 그 외에도 Nginx 인그레스 컨트롤러 설치 하는 방식은 많다. Nginx Doc 사이트 참고 해서 설치 가능 하다

Nginx Documentation - Installing Nginx Ingress Controller  

매니페스트 YAML 파일을 이용 하여 설치를 진행 하였다. 

제일 먼저 깃 허브 쿠버네티스 인그레스 파일들을 내려 받는다

git clone https://github.com/nginxinc/kubernetes-ingress.git --branch v3.1.1

# 배포 파일들 위치로 이동
cd kubernetes-ingress/deployments


이제 차례대로 아래 명령어들을 사용하여 Nginx 인그레스 컨트롤러를 배포/설치 준비를 한다

# Namespace 과 서비스 계정 생성
kubectl apply -f common/ns-and-sa.yaml

# 서비스 계정용 cluster role과 cluster role binding 생성
kubectl apply -f rbac/rbac.yaml

# Nginx 컨트롤러 설정을 위해 configMap 설정 적용
kubectl apply -f common/nginx-config.yaml

# IngressClass 리소스 생성 (없으면 Nginx 컨트롤러 실행 불가)
kubectl apply -f common/ingress-class.yaml

# 사용자 지정 리소스들 생성
kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml
kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml
kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml
kubectl apply -f common/crds/k8s.nginx.org_policies.yaml

## 기본적으로 VirtualServer, VirtualServerRoute, TransportServer 및 Policy에 대한 사용자 지정 리소스 정의를 생성해야 한다
## 그렇지 않으면 인그레스 컨트롤러 파드가 준비 상태가 되지 않는다.

# 그 외 인그레스 컨트롤러의 TCP나 UDP 로드 밸런싱을 사용하고 싶다면
kubectl apply -f common/crds/k8s.nginx.org_globalconfigurations.yaml


마지막으로 인그레스 컨트롤러 배포/설치를 진행 한다

# 기본적으로 아래 파일을 그대로 실행 하면 1 replica 인그레스 컨트롤러 파드를 생성 한다
kubectl apply -f deployment/nginx-ingress.yaml

# 마지막 단계로 loadbalancer 서비스를 통해 인그레스 컨트롤러 접근 허용을 위해
kubectl apply -f service/loadbalancer.yaml


## 선택적으로 NodePort 서비스를 통해서도 인그레스 컨트롤러 접근 가능 하다
kubectl create -f service/nodeport.yaml


설치 후 결과 확인

kubectl get all -n nginx-ingress
NAME                                READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-bcd99bfb9-w6kn7   1/1     Running   0          152m

NAME                    TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)                      AGE
service/nginx-ingress   LoadBalancer   10.233.3.51   192.168.1.40   80:30276/TCP,443:30815/TCP   150m

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-ingress   1/1     1            1           152m

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-ingress-bcd99bfb9   1         1         1       152m


이렇게 Ingress 컨트롤러는 배포가 완료 되었다. External-IP를 통해 접속이 가능 하지만 아직 아무 서비스가 링크 되어 있지 않기 때문에 아래와 같은 화면이 보인다.

image.png

컨트롤러를 다른 서비스와 활용 하기 위해 Ingress 리소스를 생성 해야 한다. 

인그레스 컨트롤러는 쿠버네티스 클러스터의 외부 트래픽을 관리하기 위한 역할을 수행 한다.  클러스터 외부에서 내부 서비스로의 트래픽 라우팅을 처리하고, 로드 밸런싱, SSL 인증서 관리 등의 기능을 제공한다.

그리고 인그레스 리소스는 인그레스 컨트롤러에 대한 구성을 정의하는 쿠버네티스 리소스이다. 인그레스 리소스는 어떤 경로로 어떤 서비스에 트래픽을 전달 할지를 정의하며, 이를 통해 클러스터 외부에서 서비스로의 트래픽을 관리할 수 있다.

테스팅을 위해 2개의 웹 사이트 서비스를 생성 하여 인그레스 리소스 설정을 통해 특정 호스트에 따라 트래픽을 전달 하겠다.

# 1번째 웹 사이트
vi my-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: waji97/ecommerce:v2                      
          ports:
            - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
:wq

      
# 2번째 웹 사이트
vi my-app2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: waji97/django:v2                       
          ports:
            - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
      
:wq


두 개의 서비스 및 Deployment 완료 후 확인

# 1번째 웹 사이트
vi my-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: waji97/ecommerce:v2                      
          ports:
            - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
:wq

      
# 2번째 웹 사이트
vi my-app2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app2
  template:
    metadata:
      labels:
        app: my-app2
    spec:
      containers:
        - name: my-app2
          image: waji97/django:v2                       
          ports:
            - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: my-app2-service
spec:
  type: ClusterIP
  selector:
    app: my-app2
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
      
:wq


# 적용 하기
kubectl apply -f my-app.yaml
deployment.apps/my-app created
service/my-app-service created

kubectl apply -f my-app2.yaml
deployment.apps/my-app2 created
service/my-app2-service created

# 현재 서비스과 Deployment들 확인 하기
NAME                           READY   STATUS    RESTARTS   AGE
pod/my-app-7d7b9b8d94-92qwc    1/1     Running   0          3m48s
pod/my-app-7d7b9b8d94-xhlvd    1/1     Running   0          3m45s
pod/my-app2-764587cdfc-fc7df   1/1     Running   0          3m54s
pod/my-app2-764587cdfc-l9h85   1/1     Running   0          3m54s

NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes        ClusterIP   10.233.0.1      <none>        443/TCP   2d
service/my-app-service    ClusterIP   10.233.46.112   <none>        80/TCP    169m
service/my-app2-service   ClusterIP   10.233.27.197   <none>        80/TCP    3m54s


이제 Ingress 리소스를 지정 해주는 작업을 한다

# YAML 매니페스트 파일을 생성 한다
vi ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - host: myapp.ingtest.com 
    http:
      paths:
      - pathType: Prefix
        path: /									
        backend:
          service:
            name: my-app-service
            port: 
              number: 80
  - host: myapp2.ingtest.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: my-app2-service
            port: 
              number: 80
              
:wq

# 위 파일을 적용
kubectl apply -f ingres.yaml 
ingress.networking.k8s.io/my-ingress created

# 생성 된 리소스 확인
kubectl get ingress
NAME         CLASS    HOSTS                                  ADDRESS   PORTS   AGE
my-ingress   <none>   myapp.ingtest.com,myapp2.ingtest.com             80      169m


이제 두 웹 사이트가 정상 적으로 작동 하고 있는지 및 Ingress가 적용이 되었는지를 확인 하기 위해 DNS 주소들에게 접속을 한다.

접속 전에 접속 하는 PC의 'hosts' 파일에 IP주소 to DNS 주소 핑을 해 줘야 한다. 그런 이유는 보통 쿠버네티스에서 인그레스 리소스를 정의할 때, 일반적으로 클러스터 외부에서 애플리케이션에 접근하기 위해 사용할 DNS 호스트 이름을 포함한다. 그러나 기본적으로 로컬 PC의 DNS Resolver는 해당 호스트 이름과 클러스터 내의 해당 IP 주소 간의 매핑을 인식하지 못할 수 있다. 로컬 PC의 'hosts' 파일에 항목을 추가함으로써, 호스트 이름과 IP 주소 간의 수동 매핑을 생성 하면 로컬 PC에서 호스트 이름을 로컬로 해석할 수 있으며 외부 DNS 해석에 의존하지 않는다.

Window 속 'hosts' 파일 경로
C:\Windows\System32\drivers\etc\hosts

Linux 속 'hosts' 파일 경로
/etc/hosts


'hosts' 파일 속 IP 매핑 후 모습

.
.
192.168.90.73 host.docker.internal
192.168.90.73 gateway.docker.internal

# 인그레스 컨트롤러의 서비스 External-IP와 매핑
192.168.1.40 myapp.ingtest.com
192.168.1.40 myapp2.ingtest.com


웹 사이트 접속 결과:

myapp.ingtest.com

image.png


myapp2.ingtest.com

image.png


//SSL 추가 및 더 디테일 한 YAML 파일 설명 그리고 /myapp /myapp2 형태의 분리 작업 남음