[kubernetes] Service & Ingress

Service 

Pod에 문제가 생기면 kubernetes는 그 Pod를 삭제 후 재생성 한다. 이때 기존 Pod IP가 낮을 확률은 매우 낮다. Kubernetes 설계 사상은 Pod는 언제든 장애에 의해서 Down 될 수 있고, 신규 Pod는 새로운 IP가 부여되기 떄문에 애플리케이션을 매번 수정을 해야하는 불편함을 없애기 위해 Service를 연결하여 사용하게 설계 되었다. 클러스터 외부에서 내부의 Pod 애플리케이션 접긍르 위한 단일 진입점 역할을 하고, Proxy(Load Balancer)의 역할처럼 연결된 Pod 들에 트래픽을 전달하는 object가 필요하다. Service object는 연결된 각각의 Pod로 Client 요청 트래픽을 포워딩 해주는 Proxy와 같다. 그래서 서비스는 selector 를 사용해서 pod의 label을 찾고 뒷단으로 연결시키기 때문에 만약 다른 pod 에서 만든 컨테이너 label 과 selector에서 찾는 값과 일치한다면 뒷단에 연결해버린다. 

공식문서 : https://kubernetes.io/ko/docs/concepts/services-networking/service/

 

Type 값과 그 동작은 다음과 같다.

  • ClusterIP: 서비스를 클러스터-내부 IP에 노출시킨다. 이 값을 선택하면 클러스터 내에서만 서비스에 도달할 수 있다. 이것은 서비스의 type을 명시적으로 지정하지 않았을 때의 기본값이다.
  • NodePort: 고정 포트 (NodePort)로 각 노드의 IP에 서비스를 노출시킨다. 노드 포트를 사용할 수 있도록 하기 위해, 쿠버네티스는 type: ClusterIP인 서비스를 요청했을 때와 마찬가지로 클러스터 IP 주소를 구성한다.
  • LoadBalancer: 클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킨다.
  • ExternalName: 값과 함께 CNAME 레코드를 리턴하여, 서비스를 externalName 필드의 내용(예:foo.bar.example.com)에 매핑한다. 어떠한 종류의 프록시도 설정되지 않는다.

Service 와 Pod의 관계 

Deployment와 Pod 생성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-pod
  template:
    metadata:
      labels:
        app: app-pod
    spec:
      containers:
      - name: app-container
        image: nginx:1.25.3
        ports:
        - containerPort: 8080

kubectl get po -o wide --show-labels | grep app-deploy
app-deploy-557bf58859-8xnhc 1/1 Running 0 55m 10.109.131.61 k8s-node2 app=app-pod
app-deploy-557bf58859-qks52 1/1 Running 0 55m 10.111.218.78 k8s-node3 app=app-pod
app-deploy-557bf58859-sj4z6 1/1 Running 0 55m 10.111.218.79 k8s-node3 app=app-pod

Deployment에 대한 Service 생성

kubectl expose deployment app-deploy --name=app-svc --port=9090 --target-port=8080

Service 정보 확인

  • 생성된 Service가 클러스터 내부에서 접근 가능하도록 ClusterIP가 할당된다.
kubectl get svc | grep app-
app-svc ClusterIP 10.104.160.238 <none> 9090/TCP 10s

Service를 통해 Pod 접근 테스트

  • Service의 ClusterIP를 이용해 요청을 보낸다.
curl 10.104.160.238:9090/hostname
Hostname : app-deploy-75d85bf8f9-vz295

기존 Deployment 재배포

kubectl rollout restart deployment app-deploy
kubectl get po -o wide | grep app-
pod/app-deploy-6f466f79cc-778p8 1/1 Running 0 119s 10.111.218.87 k8s-node3
pod/app-deploy-6f466f79cc-gdrc5 1/1 Running 0 118s 10.109.131.18 k8s-node2
pod/app-deploy-6f466f79cc-m9mcg 1/1 Running 0 116s 10.111.218.91 k8s-node3
<- Pod의 IP 주소가 바뀐다.(Pod 고정 IP X) 

curl 10.104.160.238:9090/hostname  <- Service는 Proxy 역할 
Hostname : app-deploy-6f466f79cc-m9mcg

curl 10.104.160.238:9090/hostname
Hostname : app-deploy-6f466f79cc-778p8 

curl 10.104.160.238:9090/hostname
Hostname : app-deploy-6f466f79cc-gdrc5

Service 정보 조회

kubectl describe svc app-svc
Name:                     app-svc
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=app-pod
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.104.160.238
IPs:                      10.104.160.238
Port:                     <unset> 9090/TCP
TargetPort:               8080/TCP
Endpoints:                10.109.131.18:8080,10.111.218.87:8080,10.111.218.91:8080 <- PodIP
Session Affinity:         None
Events:                   <none>

kubectl get endpoints app-svc
NAME       ENDPOINTS                                           AGE
app-svc    10.109.131.18:8080,10.111.218.87:8080,10.111.218.91:8080   16m
<- Service 이름(app-svc)과 동일하다.
  1. Service의 Endpoints
    • Service는 Selector(app=app-pod)를 기반으로 Pod를 찾아 자동으로 Endpoints를 구성한다. 
    • Service는 Endpoints를 사용하여 트래픽을 Pod로 전달한다. 
  2. Endpoints Controller
    • Pod의 상태 변경(생성, 삭제)에 따라 Endpoints를 자동으로 갱신한다. 
    • 클러스터 관리자가 수동으로 Endpoints를 관리할 필요가 없다. 
  3. Session Affinity
    • 기본적으로 None으로 설정되어 있어 요청은 무작위 Pod로 분산된다. 
    • 필요 시 ClientIP로 설정하여 클라이언트 IP에 따라 특정 Pod로 트래픽을 고정할 수 있다. 

kube-dns 정보 조회 
DNS 서비스의 ClusterIP는 10.96.0.10으로 설정되어 있으며, 53번 포트를 통해 DNS 요청을 처리한다. 

kubectl get pod,svc,ep -n kube-system -l k8s-app=kube-dns -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE
pod/coredns-5dd5756b68-7bn9m     1/1     Running   5          11d   10.111.156.92   k8s-node1   <none>
pod/coredns-5dd5756b68-rg9nv     1/1     Running   5          11d   10.111.156.88   k8s-node1   <none>

NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                       AGE   SELECTOR
service/kube-dns ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP        11d   k8s-app=kube-dns

NAME             ENDPOINTS                                              AGE
endpoints/kube-dns   10.111.156.88:53,10.111.156.92:53 + 3 more...     11d

Service IP를 DNS 이름으로 확인

Service ClusterIP로 PTR 레코드 조회 (nslookup)

kubectl run dns-pod-verify --image=busybox --restart=Never --rm -it -- nslookup 10.104.160.238
Server: 10.96.0.10
Address: 10.96.0.10:53

238.160.104.10.in-addr.arpa name = app-svc.default.svc.cluster.local

Service DNS 

DNS를 이용한 서비스 디스커버리

  • host 명령어를 사용하여 DNS 쿼리를 실행할 수 있다. Kubernetes 내에서 FQDN(완전한 도메인 이름)은 [서비스_이름].[네임스페이스].[오브젝트_타입].[도메인] 형식으로 구성된다. 
host myweb-svc.default.svc.cluster.local

이 명령어는 myweb-svc.default.svc.cluster.local 주소로 DNS 쿼리를 보내고, 해당 서비스의 IP 주소(예: 10.108.235.162)를 반환한다. 

검색 도메인 설정

cat /etc/resolv.conf
nameserver 169.213.15.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
  • /etc/resolv.conf 파일에는 search 항목이 있으며, 여기에 설정된 네임스페이스를 기준으로 DNS 쿼리가 진행된다. 
  • 예시: search default.svc.cluster.local svc.cluster.local cluster.local
  • 이를 통해 myweb-svc와 같은 이름으로 쿼리를 보내면 Kubernetes가 자동으로 해당 서비스에 대한 FQDN을 구성해 쿼리하게 된다.
  • 네임스페이스가 default가 아닌 경우, search 항목에 네임스페이스를 추가하여 DNS 쿼리를 할 수 있도록 설정해야 한다. 이를 위해 --overrides 옵션을 사용해 dnsConfig.searches에 default.svc.cluster.local을 추가할 수 있습니다.

Nodelocal DNS (DNS 캐시 서버)

  • Nodelocal DNS는 각 Kubernetes 노드에서 실행되는 DNS 캐시 서버이다. 이 캐시 서버는 DNS 쿼리가 처음 들어오면 해당 쿼리를 실제 CoreDNS 서비스로 전달하고, 그 응답을 캐시해두었다가 이후 같은 쿼리가 들어오면 빠르게 응답을 제공한다.
  • nodelocal DNS는 각 노드에 하나씩 설정되며, kubelet에 의해 관리된다.

DNS 쿼리 흐름

  • 캐시 사용 시
    • Pod에서 DNS 쿼리를 요청하면, nodelocal DNS 캐시 서버로 먼저 전달된다.
    • 캐시 서버가 이미 해당 DNS 정보를 가지고 있으면 캐시된 응답을 바로 반환한다. 
    • 캐시 서버에 정보가 없으면, CoreDNS 서비스로 쿼리를 전달하여 응답을 받고 이를 캐시한다. 
  • 캐시 미사용 시
    • Pod에서 DNS 쿼리가 CoreDNS 서비스로 바로 전달되고, CoreDNS가 실제 DNS 정보를 반환한다. 

Service - ClusterIP

기본 타입으로, 클러스터 내부에서만 접근 가능한 가상 IP를 제공한다. 

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP
  • 동작: backend-service라는 이름으로 클러스터 내부 DNS 이름(backend-service.default.svc.cluster.local)이 생성되고, 내부에서만 통신 가능.

Service - NodePort

NodePort는 애플리에킹션에 대한 외부 연결을 활성화하며 ClusterIP 서비스의 기능을 확장한다. NodePort 서비스를 생성하면 클러스터의 모든 Node에 특정한 포트(30000~32767)을 열어 외부에서 접근, 생성된 Service의 ClusterIP 로 트래픽을 Routing한다. 이때 kube-proxy가 이를 forwarding 하도록 netfilter의 chain rule을 수정한다. 웹 애플리케이션이나 API와 같이 클러슽 외부에서 엑세스해야 하는 애플리케이션에 적합하다. 

apiVersion: v1
kind: Service
metadata:
  name: nodeport-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 30007
  type: NodePort
  • 동작: 클러스터의 모든 노드에서 NodeIP:30007으로 서비스 접근 가능 하고 클라이언트가 http://<NodeIP>:30007으로 접속

Service - LoadBalancer

클라우드 서비스 공급자(CSP - AWS, GCE) 에서 제공하는 외부 Load Balancer를 이용해 클러스터 외부에서 접근 가능하도록 노출하는 서비스로 Node 앞에 위치해 각 Node들로 트래픽을 분산하는 역할을 한다. LoadBalancer 서비스는 NodePort 서비스 위에 적용한다. L4 LoadBalancer 가 생성되고, ClusterIP 서비스 및 NodePort 서비스가 암시적으로 생성된다. Public으로 사용 가능한 IP 주소 및 DNS 주소를 제공하여 Private IP 주소 및 NodePort 포트를 통해 클러스터의 Node에 트래픽을 Load Balancing 하고 전달한다. 또한 클라우드 환경이 아닌 온프레미스(VM) 환경에서 LoadBalancer를 사용할 경우 제공한 Public 주소를 제공할 수 있는 MetalLB 모듈을 설치해주어야 이용 가능하다. 

apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

MetalLB

MetalLB는 Kubernetes에서 클라우드 환경의 LoadBalancer 서비스를 온프레미스 환경에서도 구현할 수 있도록 도와주는 네트워크 로드밸런서 솔루션이다. 클라우드 제공자의 네이티브 LoadBalancer 기능을 대체하여 외부 트래픽을 Kubernetes 클러스터 내부로 라우팅하는 역할을 한다. MetalLB는 L2모드(Layer2)와 BGP 두 가지 운영 모드를 제공한다. 

MetalLB 컴포넌트 

  • Controller(Deployment) : 구성된 IP Pool에서 로드밸런싱을 수행할 EXTERNAL-IP 주소를 할당하는 역할 
  • Speaker(DaemonSet) : Layer2 or BGP 모드를 통해 할당된 IP를 알리는 역할 수행. speaker pod는 node IP를 사용

Layer2 모드

  • 디폴트 모드로, 소규모 클러스터(노드 10대 이하)에 적합하다. 
  • Layer2(이더넷) 네트워크에서 작동하며, ARP를 사용해 특정 IP를 노드의 MAC 주소에 매핑한다. 
  • 물리적 스위치가 필요하지 않으며, 간단히 IP 주소를 클러스터 노드 중 하나에 바인딩하여 동작한다. 

트래픽 흐름

  1. 클라이언트가 Speaker Pod가 바인딩된 IP로 요청을 보냄.
  2. Speaker Pod는 트래픽을 Controller로 전달.
  3. Controller는 요청을 NodePort로 전달.
  4. NodePort는 서비스에 연결된 Pod들로 요청을 분배.

구성 예제

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.240-192.168.1.250
  • 192.168.1.240-192.168.1.250의 IP 범위에서 서비스에 사용할 IP가 동적으로 할당된다. 

BGP 모드

  • 대규모 클러스터(노드 10대 이상)에서 적합하며, **BGP (Border Gateway Protocol)**를 사용.
  • BGP를 통해 클러스터 네트워크와 외부 네트워크 간의 경로를 광고.
  • L3 스위치나 BGP 라우터가 필요하며, 스위치가 로드밸런서 역할을 수행.

트래픽 흐름

  1. 클라이언트가 **L3 스위치(BGP 라우터)**에 요청을 보냄.
  2. 스위치가 MetalLB Speaker에게 트래픽을 라우팅.
  3. Speaker는 요청을 적절한 NodePort로 전달.
  4. NodePort가 연결된 서비스와 Pod들로 요청을 분배.

구성 예제

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    peers:
    - peer-address: 192.168.1.1
      peer-asn: 64512
      my-asn: 64512
    address-pools:
    - name: default
      protocol: bgp
      addresses:
      - 192.168.1.240-192.168.1.250
  • peer-address는 L3 스위치의 IP를 나타낸다.

Layer2 vs BGP 비교

적합한 환경 소규모 클러스터 (10대 미만 노드) 대규모 클러스터 (10대 이상 노드)
필요한 인프라 별도의 네트워크 장비 필요 없음 L3 스위치 또는 BGP 라우터 필요
작동 방식 ARP를 이용해 IP를 노드 MAC에 바인딩 BGP로 경로를 외부 네트워크에 광고
유연성 설정이 간단하고 빠르게 배포 가능 대규모 네트워크에서 고성능 제공

Service - ExternalName

DNS 이름을 다른 외부 도메인 이름으로 매핑하는데 사용한다. 사용 예로는 : 외부서비스(MySQL, API등) 와 Kubernetes 서비스를 연결하는데 있다. 

apiVersion: v1
kind: Service
metadata:
  name: externalname-service
spec:
  type: ExternalName
  externalName: api.example.com
  • 동작: externalname-service.default.svc.cluster.local을 호출하면 api.example.com으로 리다이렉션

External IP

External IP는 클러스터 외부에서 접근 가능한 IP 주소이다. 클러스터 관리자가 제공하거나 설장한 외부 IP로, Kubernetes가 직접 관리하지 않는다. External IP로 들어오는 트래픽은 Kubernetes 서비스의 엔드포인트(Backend Pod)로 전달된다. Kubernetes의 모든 서비스 타입(ClusterIP, NodePort, LoadBalancer 등)과 함께 사용 가능하며, 외부 IP는 클러스터 노드 중 하나이상으로 트래픽을 라우팅한다. 외부에서 externalIP: 포트 형태로 서비스를 사용할 수 있다. 

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80       # 클라이언트가 접근할 포트
      targetPort: 9376  # 백엔드 Pod가 사용하는 실제 포트
  externalIPs:
    - 80.11.12.10  # 외부에서 접근 가능한 IP
  • 클라이언트는 80.11.12.10:80으로 접근
  • Kubernetes는 요청을 9376 포트로 서비스의 엔드포인트 중 하나(연결된 Pod)로 전달

Ingress 

공식문서: https://kubernetes.io/ko/docs/concepts/services-networking/ingress/

인그레스 컨트롤러

그레스 리소스가 작동하려면, 클러스터는 실행 중인 인그레스 컨트롤러가 반드시 필요하다.

kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 다른 타입과 달리 인그레스 컨트롤러는 클러스터와 함께 자동으로 실행되지 않는다. 클러스터에 가장 적합한 인그레스 컨트롤러 구현을 선택하는데 이 페이지를 사용한다. 프로젝트로서 쿠버네티스는 AWS, GCE nginx 인그레스 컨트롤러를 지원하고 유지한다.

인그레스란?

인그레스는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출한다. 트래픽 라우팅은 인그레스 리소스에 정의된 규칙에 의해 컨트롤된다.

서비스의 타입은 일반적으로 NodePort 타입이다. 인그레스는 외부에서 서비스로 접속이 가능한 URL, 로드 밸런스 트래픽, SSL / TLS 종료 그리고 이름-기반의 가상 호스팅을 제공하도록 구성할 수 있다. 인그레스 컨트롤러는 일반적으로 로드 밸런서를 사용해서 인그레스를 수행할 책임이 있으며, 트래픽을 처리하는데 도움이 되도록 에지 라우터 또는 추가 프런트 엔드를 구성할 수도 있다.

인그레스는 임의의 포트 또는 프로토콜을 노출시키지 않는다. HTTP와 HTTPS 이외의 서비스를 인터넷에 노출하려면 보통 Service.Type=NodePort 또는 Service.Type=LoadBalancer 유형의 서비스를 사용한다.

 

service/networking/minimal-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

rules

  • 라우팅 규칙을 정의한다. 
  • HTTP 요청에 대한 조건과 이를 처리할 방법을 설정한다. 

pathType (경로 유형)

  1. Exact
    • URL 경로를 대소문자까지 엄격히 일치시켜 매칭한다. 
    • 예: /TestPath와 /testpath는 서로 다른 경로로 인식.
  2. Prefix
    • URL 경로의 접두사가 일치하는지 확인합니다.
    • / 기준으로 경로를 나누고, 요소별로 매칭.
    • 대소문자를 구분하며, 요청 경로의 요소가 지정된 접두사와 일치하면 매칭.
    • 예: /test는 /test/example과 매칭되지만, /testing과는 매칭되지 않음.
  3. implementationSpecific
    • 경로 매칭 방식이 Ingress Controller(예: Nginx) 구현에 따라 다릅니다.
    • 컨트롤러에 따라 Exact 또는 Prefix처럼 처리될 수 있음.

backend (트래픽 처리 대상)

  1. resource
    • Kubernetes 리소스 그룹을 설정할 수 있다.
    • 구성 요소
      • apiGroup: API 그룹 이름
      • kind: 리소스 유형
      • name: 리소스 이름
  2. service
    • 서비스 이름과 포트를 설정합니다.
    • 구성 요소
      • name: 라우팅될 서비스의 이름
      • port
        • name: 서비스에서 지정한 포트 이름
        • number: 실제 포트 번호

인그레스에는 apiVersion, kind, metadata  spec 필드가 명시되어야 한다. 인그레스 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다. 설정 파일의 작성에 대한 일반적인 내용은 애플리케이션 배포하기, 컨테이너 구성하기, 리소스 관리하기를 참조한다. 인그레스는 종종 어노테이션을 이용해서 인그레스 컨트롤러에 따라 몇 가지 옵션을 구성하는데, 그 예시는 재작성-타겟 어노테이션이다. 서로 다른 인그레스 컨트롤러는 서로 다른 어노테이션을 지원한다. 지원되는 어노테이션을 확인하려면 선택한 인그레스 컨트롤러의 설명서를 검토한다.

인그레스 사양 에는 로드 밸런서 또는 프록시 서버를 구성하는데 필요한 모든 정보가 있다. 가장 중요한 것은, 들어오는 요청과 일치하는 규칙 목록을 포함하는 것이다. 인그레스 리소스는 HTTP(S) 트래픽을 지시하는 규칙만 지원한다.

인그레스 규칙

각 HTTP 규칙에는 다음의 정보가 포함된다.

  • 선택적 호스트. 이 예시에서는, 호스트가 지정되지 않기에 지정된 IP 주소를 통해 모든 인바운드 HTTP 트래픽에 규칙이 적용 된다. 만약 호스트가 제공되면(예, foo.bar.com), 규칙이 해당 호스트에 적용된다.
  • 경로 목록 (예, /testpath)에는 각각 service.name  service.port.name 또는 service.port.number 가 정의되어 있는 관련 백엔드를 가지고 있다. 로드 밸런서가 트래픽을 참조된 서비스로 보내기 전에 호스트와 경로가 모두 수신 요청의 내용과 일치해야 한다.
  • 백엔드는 서비스 문서 또는 사용자 정의 리소스 백엔드에 설명된 바와 같이 서비스와 포트 이름의 조합이다. 규칙의 호스트와 경로가 일치하는 인그레스에 대한 HTTP(와 HTTPS) 요청은 백엔드 목록으로 전송된다.

defaultBackend 는 종종 사양의 경로와 일치하지 않는 서비스에 대한 모든 요청을 처리하도록 인그레스 컨트롤러에 구성되는 경우가 많다.

간단한 팬아웃(fanout)

팬아웃 구성은 HTTP URI에서 요청된 것을 기반으로 단일 IP 주소에서 1개 이상의 서비스로 트래픽을 라우팅 한다. 인그레스를 사용하면 로드 밸런서의 수를 최소로 유지할 수 있다. 예를 들어 다음과 같은 설정을 한다.

service/networking/simple-fanout-example.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

인그레스 컨트롤러는 서비스(service1, service2)가 존재하는 한, 인그레스를 만족시키는 특정한 로드 밸런서를 프로비저닝한다. 

도메인 없이 호스트 필드를 사용하여 외부 접근 설정

도메인을 구입하지 않고도 Ingress를 통해 외부에서 접근할 수 있게 하는 방법이다. 

  • 방법 1: curl --resolve 옵션을 사용
    • curl --resolve <host>:<port>:<ingress_ip> <host> 명령을 사용하여, 특정 도메인 이름과 포트를 지정하고 해당 IP로 요청을 보낼 수 있다. 
    • curl --resolve www.test.com:80:192.168.100.106 www.test.com
      여기서 www.test.xyz는 도메인처럼 보이지만 실제로는 호스트 IP 주소를 지정하여 요청을 보낸다. 
  • 방법 2: /etc/hosts 파일 수정
    • 로컬 환경에서만 사용할 때, /etc/hosts 파일에 도메인과 IP를 직접 추가하여 로컬 DNS를 우회할 수 있다. 
    • /etc/hosts 파일에 도메인과 IP를 추가하여 로컬에서 특정 도메인에 대한 요청을 로컬 IP로 우회하려면, nsswitch.conf 파일에서 hosts 항목이 files dns로 설정되어 있어야 한다. 이를 통해 시스템이 먼저 /etc/hosts 파일을 확인하고, 해당 도메인에 대해 로컬에서 지정한 IP를 우선적으로 사용하도록 할 수 있다. 
    • 예시: 192.168.100.106 www.test.com 를 /etc/hosts 파일에 추가한 뒤, curl http://www.test.com로 요청을 보낸다 
  • 방법 3: nip.io와 같은 와일드 카드 DNS 서비스 사용
    • nip.io는 URL의 IP를 기반으로 한 DNS 서비스로, IP 주소를 포함한 도메인을 생성하여 DNS 해석 없이도 쉽게 테스트할 수 있다. 
    • http://app-192-168-100-106.nip.io로 접근하여, Ingress에서 설정한 대로 요청이 myweb-svc-np 서비스로 라우팅된다. 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  rules:
    - host: '*.nip.io'
      http:
        paths:
          - pathType: Prefix
            path: /
            backend:
              service:
                name: myweb-svc-np
                port:
                  number: 80

이름 기반의 가상 호스팅

이름 기반의 가상 호스트는 동일한 IP 주소에서 여러 호스트 이름으로 HTTP 트래픽을 라우팅하는 것을 지원한다.

service/networking/name-virtual-host-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

TLS

TLS 개인 키 및 인증서가 포함된 시크릿(Secret)을 지정해서 인그레스를 보호할 수 있다. 인그레스 리소스는 단일 TLS 포트인 443만 지원하고 인그레스 지점에서 TLS 종료를 가정한다(서비스 및 해당 파드에 대한 트래픽은 일반 텍스트임). 인그레스의 TLS 구성 섹션에서 다른 호스트를 지정하면, SNI TLS 확장을 통해 지정된 호스트이름에 따라 동일한 포트에서 멀티플렉싱 된다(인그레스 컨트롤러가 SNI를 지원하는 경우). TLS secret에는 tls.crt  tls.key 라는 이름의 키가 있어야 하고, 여기에는 TLS에 사용할 인증서와 개인 키가 있다. 예를 들어 다음과 같다.

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded c

인그레스에서 시크릿을 참조하면 인그레스 컨트롤러가 TLS를 사용하여 클라이언트에서 로드 밸런서로 채널을 보호하도록 지시한다. 생성한 TLS 시크릿이 https-example.foo.com 의 정규화 된 도메인 이름(FQDN)이라고 하는 일반 이름(CN)을 포함하는 인증서에서 온 것인지 확인해야 한다.

 

service/networking/tls-example-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80