IT/Kubernetes

[Kubernetes] Kubernetes Study: "기본 오브젝트 - Service"

wookiist 2021. 6. 27. 13:58

Prologue

본 포스트는 인프런 쿠버네티스 스터디 그룹에서 진행하는 스터디 자료의 일환으로 작성하였습니다. 기본적으론 [대세는 쿠버네티스] 강의를 보고 내용을 정리합니다. 그리고 제 경험이나 이해를 곁들여 포스트를 작성했습니다. 그동안 공식 문서나 블로그 포스트, CKA 강의 등 다양한 경로로 쿠버네티스를 익혀왔지만, 한국어로 잘 정리된 강좌를 한번 듣고 깔끔하게 다듬어보는 시간을 가지면 좋겠다는 생각이 들었습니다.

강의와는 조금 다를 수 있지만, 쿠버네티스 공식 문서를 보고 내용을 정리해보겠습니다.

이번 포스트에선 "기본 오브젝트 - Service"를 다뤄봅니다.

Service

서비스는 파드 집합에서 실행중인 애플리케이션을 네트워크로 노출하는 방법입니다. 앞서 설명드렸듯, 파드는 재생성이 되면 클러스터 내부에서 사용하는 IP가 변경됩니다. 또한 외부로 노출되는 IP도 갖고 있지 않죠. 파드의 라이프사이클은 언제나 운용 상태에 있을 순 없기 때문에 (업그레이드 등) 파드가 재실행되었을 때 IP를 매번 확인해야 한다면 엄청나게 비효율적이며, 합리적이지 못한 방법일 것입니다.

이러한 문제를 서비스는 해결합니다. 쿠버네티스에서 서비스는 파드의 집합과 파드에 접근할 수 있는 정책을 정의하는 개념입니다. 쉽게 말해, 파드에 접근하려면 서비스를 이용하라는 것이죠. 예를 들어, 백엔드와 프론트엔드로 구성된 일반적인 환경을 생각해보겠습니다. 프론트엔드 클라이언트가 백엔드에 접근할 때, 연결해야 하는 IP의 주소를 어떻게 찾아서 접근할 수 있을까요? 만약 파드의 IP를 가지고 이러한 구조를 만들었다면 매우 골치가 아플 겁니다. 하지만 서비스를 이용한다면 이야기가 쉬워집니다. 백엔드는 서비스를 이용해 자신에 접근할 수 있도록 정책을 설정합니다. 특정 서비스를 이용하면 백엔드 접근이 가능해진다는 것입니다. 이렇게 구성해두면, 프론트엔드는 백엔드를 찾을 노력을 할 필요가 없습니다. 그저 백엔드와 연결해주는 서비스를 통해 필요한 통신을 수행하면 되기 때문입니다.

강의 내용

파드에도 IP가 부여되는데 굳이 서비스를 이용해야 하는 이유가 무엇일까요? 앞서 설명드렸듯이 파드의 IP는 파드가 재생성되었을 때, 변경됩니다. 따라서 그 신뢰성이 떨어집니다. 서비스의 IP로 접근을 하면 언제나 그 서비스와 연결된 파드에 접근할 수 있게 해준다는 신뢰성을 주기 때문입니다. 또한 파드를 여러 개 연결할 수도 있습니다. 즉, 같은 IP로 연결된 파드들을 로드 밸런싱 해주는 역할도 수행한다는 이점도 있습니다.

쿠버네티스 서비스의 타입은 크게 3가지가 있습니다. 각각에 대해 알아보겠습니다.

ClusterIP

이름 그대로 쿠버네티스 클러스터 내에서만 접근이 가능한 IP입니다. 클러스터 내에 있는 다른 오브젝트들은 이 서비스 IP를 통해서 파드에 접근이 가능하지만, 클러스터 외부에서는 이 IP로 접근할 수 없습니다.

서비스 타입의 기본값으로, 매니페스트 파일에 타입을 넣어주지 않으면 서비스는 기본적으로 ClusterIP로 동작합니다.

아래의 매니페스트 파일로 서비스를 생성하면, app: nginx 인 레이블을 갖는 파드에 연결되며, 서비스의 8000번 포트로 파드의 80 포트를 연결해주는 서비스가 생성됩니다.

apiVersion: v1
kind: Service
metadata:
    name: label-demo
    labels:
        environment: production
        app: nginx
spec:
    selector:
        app: nginx
    ports:
    - port: 8000 # 이 서비스의 포트를 정의
        targetPort: 80 # 이 서비스의 포트(port)를 컨테이너 내부에서 어떤 포트(targetPort)와 연결할 것인지 정의
    **type: ClusterIP**

ClusterIP는 보통 인가된 운영자 및 사용자, 내부에서 사용하는 대시보드, 파드의 상태 디버깅 등에 이용합니다.

NodePort

이름 그대로 노드의 포트를 활용하는 방법입니다. 파드를 외부로 노출해야 할 때 사용하는 가장 일반적인 방법입니다. NodePort에서 정의한 포트는 클러스터를 구성하는 모든 노드에서 접근이 가능합니다. 즉, 실제 파드가 실행 중인 노드 뿐만 아니라 파드가 실행 중이지 않은 노드에서도 같은 포트를 사용하면 해당 서비스에 연결되는 것입니다. 서비스는 파드로 접근을 하게 해주기 때문에 결국 어떤 노드로 접근하건 포트만 같다면 같은 파드로 도달하게 됩니다. 아래 매니페스트 파일을 확인해보겠습니다.

apiVersion: v1
kind: Service
metadata:
    name: label-demo
    labels:
        environment: production
        app: nginx
spec:
    selector:
        app: nginx
    ports:
    - port: 8000 # 이 서비스의 포트를 정의
        targetPort: 80 # 이 서비스의 포트(port)를 컨테이너 내부에서 어떤 포트(targetPort)와 연결할 것인지 정의
    **nodePort: 30000** # NodePort는 30000 ~ 32767 까지만 할당 가능
    **type: NodePort**

주의해야 할 점은 NodePort로 할당할 수 있는 포트는 30000 부터 32767 까지입니다. 이외의 포트를 할당하려고 하면 서비스가 생성되지 않습니다.

추가로, 위의 매니페스트 정의에 externalTrafficPolicy: Local 이라는 정의를 추가하면, NodePort 서비스는 A라는 노드의 IP로 접근했을 때, A 노드에 서비스와 연결된 파드가 실행 중인 경우, 항상 그 파드에 연결되도록 설정할 수 있습니다. 추가적으로 만들어질 수 있는 번잡한 트래픽을 줄이는 데 의미가 있습니다.

NodePort는 내부망 연결, 데모나 임시 외부 연결용으로 활용하게 됩니다.

LoadBalancer

LoadBalancer 타입은 on-premise 환경의 클러스터에서는 기본적으로 사용할 수 없습니다. 이를 이용하려면 MetalLB 등의 플러그인을 설치해야 합니다. 보통 GCP, Azure, AWS 등의 퍼블릭 클라우드 서비스를 이용하면, LoadBalancer 타입을 바로 이용할 수 있습니다. 그러나 외부 IP를 하나하나 할당해주는 것은 비용적인 측면에서도 만만치 않기 때문에 유의해야 합니다.

LoadBalancer 타입으로 서비스를 생성하면, 로드 밸런서가 생성되며, 외부 IP로 접근해오는 트래픽을 서비스로 연결해줍니다. 이후의 내용은 NodePort와 동일합니다.

apiVersion: v1
kind: Service
metadata:
    name: label-demo
    labels:
        environment: production
        app: nginx
spec:
    selector:
        app: nginx
    ports:
    - port: 8000 # 이 서비스의 포트를 정의
        targetPort: 80 # 이 서비스의 포트(port)를 컨테이너 내부에서 어떤 포트(targetPort)와 연결할 것인지 정의
    **type: LoadBalancer**

LoadBalancer 타입은 내부 IP를 노출하지 않고 외부 시스템에 노출하기를 원할 때 사용하게 됩니다.

마무리

이렇게 해서 인프런 강의의 "기본 오브젝트 - Service"를 다뤄봤습니다. 내용이 많이 부실하고, 설명이 어렵게 되어 있는 등의 문제가 있을 것으로 보입니다. 추후 수정을 통해 다듬어보겠습니다.

여기까지 따라오시느라 고생이 많으셨습니다. 만약 이 글이 도움이 되셨다면 글 좌측 하단의 하트❤를 눌러주시면 감사하겠습니다.

혹시라도 글에 이상이 있거나, 이해가 가지 않으시는 부분, 또는 추가적으로 궁금하신 내용이 있다면 주저 마시고 댓글💬을 남겨주세요! 빠른 시간 안에 답변을 드리겠습니다 😊

반응형