Justin의 개발 로그
article thumbnail
Published 2024. 2. 19. 16:03
쿠버네티스 서비스 Kubernetes

서비스(Service) : 파드를 연결하고 외부에 노출

  • 파드가 K8s 클러스터에 배포되면 쿠버네티스 네트워킹의 기본 규칙(쿠버네티스 네트워크 플러그인에 의해)에 의해 클러스터 내의 다른 파드와 직접 통신할 수 있다.
  • 파드는 자발적, 비자발적으로 종료되고, 새로운 파드가 자동 생성될 수 있다. 이로인해 쿠버네티스 파드에 직접 IP를 부여하지 않는다.
  • 대신 서비스를 통해 내구성 있는 IP(또는 도메인)와 포트를 쿠버네티스 클러스터에 할당하고, 서비스의 엔드포인트를 적절한 파드(Pods)에 자동으로 매핑하는 방식을 사용한다. 이것이 바로 서비스 API가 필요한 이유이다.
  • kube-proxy 서비스가 클러스터의 각 노드에서 실행되어 iptables 규칙을 관리(조작)한다. 즉, kube-proxy가 서비스를 관리한다고 볼 수 있다.

 

 

(디플로이먼트(또는 레플리카셋, 파드)를 통해 생성된)
파드(Pod)는 내부IP가 자동 할당되며, 컨테이너포트는 YAML의 설정값으로 할당된다.

spec:
   containers:
   - name: nginx
     image: nginx:1.10
     ports:
     - containerPort: 80

 

YAML 파일에서 containerPort를 정의했다고 이 포트가 바로 외부에 노출되진 않는다. 
이 노트에 설정된 containerPort를 외부에서 접근하거나, 다른 내부의 디플로이먼트(레플리카셋, 파드 포함)에서 내부적으로 접근하려면 서비스(service)라고 부르는 쿠버네티스 오브젝트를 생성해야 한다.

 

서비스는 파드에 접근하기 위한 규칙이며, 애플리케이션을 배포하기 위해서는 반드시 알아야 한다.

 

서비스(Service) 핵심 기능

  • 여러 개의 파드에 쉽게 접근할 수 있도록 고유한 도메인 이름을 부여한다.
  • 여러 개의 파드에 접근할 때, 요청을 분산하는 로드 밸런서 기능을 수행한다.
  • 클라우드 플랫폼의 로드 밸런서, 클러스터 노드의 포트 등을 통해 파드를 외부로 노출한다.
서비스 설명 용도
ClusterIP 쿠버네티스 내부에서만 파드들(Pods)에 접근할 때 사용
외부로 파드를 노출하지 않기 때문에 내부에서만 사용되는 파드에 적합
DNS를 통해 파드에 연결할 수 있어서 내부 호출에 가장 적합
서비스 타입을 명시하지 않을 때 기본값
쿠버네티스 내부 통신용
NodePort 외부에 접근할 수 있는 서비스 타입
파드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개방한다.
특정 포트로 접근하도록 설정할 수도 있고, 랜덤으로 포트가 할당되도록 할 수도 있다.
외부에서 파드 접근 필요
LoadBalancer 클라우드 플랫폼에서 제공되는 로드 밸런서를 동적으로 프로비저닝해 파드에 연결
NodePort 타입과 마찬가지로 외부에서 파드에 접근할 수 있는 서비스 타입
일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 사용할 수 있다.
클라우드 플래폼 운영 환경
ExternalName 쿠버네티스를 외부 시스템과 연동해야 할 때 사용
서비스가 외부 도메인을 가리키도록 설정할 수 있다.
예)
external-svc -> api.outofdomain.com
 

 

ClusterIP 타입

svc-clusterip.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
  - name: web-port
    port: 8080
    targetPort: 80
  selector:
    app: webserver
  type: ClusterIP
  • spec.selector : 어떠한 라벨을 가진 파드에 접근할 수 있게 만들지 설정, 위에서는 app: webserver 라는 라벨을 가지는 파드들의 집합에 접근할 수 있는 서비스를 생성한다.
  • spec.ports.port: 서비스에 할당되는 port, 생성된 서비스는 고유한 클러스터IP가 할당된다.
  • spec.ports.targetPort: selector 항목에서 정의한 라벨에 의해 접근 대상이 된 파드들이 내부적으로 사용하고 있는 포트를 입력한다. 파드 yaml에 정의된 containerPort와 같은 값으로 설정해야 한다.
  • spec.type: 서비스의 타입 

 

ClusterIP 타입 설명

  • 내부 통신용으로 쿠버네티스 클러스터 내에서만 접근 가능하다.
  • 즉, 내부 pod를 통해서만 ClusterIP를 사용할 수 있다.
  • ClusterIP 서비스에 연결된 파드들이 둘 이상인 경우 로드밸런싱이 된다.
  • 서비스이름 또는 IP + 포트로 접근한다.
    예) svc-clusterip:8080 또는 10.xx.xx.xx:8080
  • ClusterIP 서비스를 외부에 노출하려면 NodePort나 LoadBalancer 타입의 서비스를 생성해야 한다.
  • 동일한 네임스페이스의 다른 파드에서 해당 서비스에 접근하는 경우 서비스 네임을 통해 간단히 접근할 수 있다.
    http://svc-clusterip
  • 동일 클러스터 내의 다른 네임스페이스에서 서비스를 찾는 경우 DNS 패턴은 <service_name>.<namespace_name>.svc.cluster.local 이다.
  • 동일 클러스터 내의 클라이언트(파드)는 서비스를 호출할 때 DNS 이름을 사용하면 ClusterIP에 할당된 IP가 변경되어도 문제없이 엔드포인트를 원하는 파드에 연결할 수 있다.

 

NodePort 타입

svc-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-nodeport
spec:
  ports:
  - name: web-port
    port: 8080
    targetPort: 80
  selector:
    app: webserver
  type: NodePort
  • 외부에 노출되는 것을 제외하고, ClusterIP와 동일 
  • NodePort 타입의 서비스는 ClusterIP의 기능을 포함한다. 즉, 내부 IP와 DNS 이름(서비스명:포트)으로도 접근할 수 있다.

 

NodePort 타입 설명

$kubctl apply -f svc-nodeport.yaml
service/svc-nodeport craeted

$kucectl get services
NAME         TYPE     CLUSTER-IP   EXTERNAL-IP  PORT(S)        AGE
svc-nodeport NodePort 10.110.9.111 <none>       8080:31514/TCP 15s
  • PORT(S)의 31514는 모든 노드에서 동일하게 접근할 수 있는 포트를 의미한다. 즉, 클러스터의 모든 노드에 내부IP 또는 외부 IP를 통해 31514 포트로 접근하면 서비스에 연결된다.
  • 개방되는 포트는 30000~32768 중에서 랜덤으로 선택된다. YAML에 nodePort: 31000 처럼 포트를 강제 할당할 수도 있다.
  • 실제 운영 환경에서 NodePort로 서비스를 외부에 제공하는 경우는 많지 않다.
  • 운영 환경에서 NodePort의 포트 번호를 80, 443으로 설정하기에는 SSL 인증서 적용, 라우팅 등과 같은 복잡한 설정을 적용하기가 어렵기 때문
  • NodePort를 바로 외부에 연결하기 보다는 인그레스(Ingress) 오브젝트를 통해 NodePort를 연결하는 경우가 많다.

 

 

LoadBalancer 타입

  • 서비스를 생성과 동시에 클라우드 플랫폼에 로드 밸런서를 새롭게 생성해 파드와 연결한다.
  • NodePort를 사용하려면 각 노드의 IP를 알아야만 파드에 접근할 수 있지만, LoadBalancer 타입은 클라우드 플랫폼으로부터 도메인 이름과 IP를 할당받기 때문에 NodePort 보다 쉽게 파드에 접근할 수 있다.
  • 가상 머신이나 온프레미스 환경에서는 사용하기 어렵다.
    *MetalLB, LBaaS 등과 같이 온프레미스 환경에서 LoadBalancer 서비스를 사용할 수 있는 방법이 있다.
svc-lv.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-lb
spec:
  type: LoadBalancer
  loadBalancerIP: 13.12.21.31
  loadBalancerSourceRanges:
  - 142.43.0.0/16
  - 10.0.0.0/8
  ports:
  - name: web-port
    port: 80
    targetPort: 80
  selector:
    app: webserver
  • ports.port 는 로드 밸런서에 접근하기 위한 포트이다.
  • spec.loadBalancerIP : 로드밸런서에 고정 IP 주소를 할당하는 서비스 설정입니다.
  • spec.loadBalancrSourceRanges :  보안 그룹이나 방화벽 규칙처럼 동작하여, 지정된 IP 주소 범위에서만 서비스에 접근하도록 제한한다. 보안 수준을 높이고, 무단 액세스를 방지할 수 있다.
$kubectl apply -f svc-lb.yaml
service/svc-lb craeted.

$kucectl get services
NAME       TYPE         CLUSTER-IP   EXTERNAL-IP              PORT(S)        AGE
svc-lb     LoadBalancer 10.110.60.11 a5f11.elb.amazonaws.com  80:32001/TCP   15s
  • NodePort, ClusterIP와 동일하게 Cluster-IP가 할당되며, IP:port 또는 서비스명:포트로 서비스에 접근할 수 있다.
  • 클라우드 플랫폼으로부터 EXTERNAL-IP가 자동 할당된다.
  • EXTERNAL-IP:port(80)로 파드에 접근할 수 있다.
  • 로드 밸런싱 기능도 NodePort, ClusterIP와 마찬가지로 자동으로 적용된다.

 

 

인그레스(Ingress)

인그레스 : 외부에서 내부로 향하는 것.

인그레스 트래픽은 외부에서 서버로 유입되는 트래픽을 의미하며, 인그레스 네트워크는 인그레스 트래픽을 처리하기 위한 네트워크이다.

 

서비스 오브젝트가 외부 요청을 받아들이기 위한 것이라면, '인그레스'는 외부 요청을 어떻게 처리할 것인지 네트워크 7계층 레벨에서 정의하는 쿠버네티스 오브젝트이다.

인그레스 주요 기능

  • 외부 요청의 라우팅 : /apple, /apple/red 등과 같이 특정 경로로 들어온 요청을 어떤 서비스로 전달할지 정의하는 라우팅 규칙을 설정할 수 있다.
  • 가상 호스트 기반의 요청 처리 : 같은 IP에 대해 다른 도메인 이름으로 요청이 도착했을 때 어떻게 처리할 것인지 정의할 수 있다.
  • SSL/TCL 보안 연결 처리 : 여러 개의 서비스로 요청을 라우팅할 때, 보안 연결을 위한 인증서를 쉽게 적용할 수 있다.

인그레스 자체의 기능은 어느 정도 정해져 있지만, 인그레스 요청을 처리할 서버로 무엇을 선택하느냐에 따라 기능이 조금씩 달라진다.

 

인그레스를 사용하는 이유

  • 인그레스를 사용하면 URL 엔드포인트 하나로 여러 디플로이먼트를 외부에 노출시킬 수 있다.
  • 라우팅 정의나 보안 연결 등과 같은 세부 설정을 각 디플로이먼트에 일일이 적용할 필요 없이 하나의 설정 지점에서 처리 규칙을 관리할 수 있다.
  • 클라우드 플랫폼 자체에서 관리해주는 인증서를 인그레스 컨트롤러에 적용할 수 있다.

 

ingress-example.yaml

apiVersion: v1
kind: Ingress
metadata:
  name: ingress-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: alicek106.example.com   # [1]
    http:
      paths:
      - path: /echo-hostname      # [2]
        backend:
          serviceName: hostname-service   #[3]
          servicePort: 80

 

  • [1] host : 해당 도메인 이름으로 접근하는 요청에 대해서 처리 규칙을 적용한다. 여러 도메인 적용 가능
  • [2] path : 해당 경로에 들어온 요청을 어느 서비스로 전달할 것인지 정의한다. 위의 경우 /echo-hostname 경로로 들어온 요청을 backend에 정의된 서비스로 전달한다.
  • 인그레스는 규칙을 정의하는 선언적인 오브젝트일 뿐, 외부 요청을 받아들일 수 있는 서버가 아니다.
  • 인그레스는 인그레스 컨트롤러(Ingress Controller)에 적용하기 위한 규칙은 생성하는 것이며, 인그레스 컨트롤러 서버에 적용해야만 그 규칙을 사용할 수 있다.

 

인그레스 컨트롤러(Ingress Controller)

쿠버네티스 인그레스는 반드시 인그레스 컨트롤러라는 서버와 함께 사용해야 한다.
대표적인 인그레스 컨트롤러는 Nginx 웹 서버 인그레스 컨트롤러가 있다.

 

$kucectl get svc -n ingress-nginx
NAME           TYPE         CLUSTER-IP   EXTERNAL-IP              PORT(S)        AGE
ingress-nginx  LoadBalancer 10.110.60.12 a21.elb.amazonaws.com  80:32010/TCP   15s

 

profile

Justin의 개발 로그

@라이프노트

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!