반응형

목차

  1. 서비스란
  2. 서비스 생성
  3. 서비스 조회 및 테스트
  4. kubectl exec
  5. 서비스 세션 어피니티 구성
  6. 한 서비스로 여러 포트 노출하기
  7. 이름이 지정된 포트 사용

서비스란

쿠버네티스 서비스는 웹 서버 또는 데이터베이스 실행과 같은 동일한 작업을 수행하는 Pod 집합을 함께 그룹화하는 추상화입니다. 서비스를 생성하면 클라이언트가 클러스터의 개별 위치에 관계없이 이러한 포드에 액세스할 수 있는 안정적이고 지속적인 진입점 또는 "터치포인트"를 생성할 수 있습니다.

 

서비스를 만들 때 Kubernetes는 서비스에 안정적인 IP 주소와 포트를 할당합니다. 이는 서비스 수명 동안 일정하게 유지되므로 클라이언트가 기본 Pod의 IP 주소 또는 포트 변경에 대해 걱정하지 않고 안정적으로 연결할 수 있습니다.

 

클라이언트는 안정적인 IP 주소 및 포트에 연결하여 서비스에 액세스합니다. 그런 다음 서비스는 클라이언트의 요청을 관리하는 포드 중 하나로 라우팅하며 실제로 원하는 기능을 제공합니다.

 

클라이언트는 서비스의 IP 주소 및 포트와만 상호 작용하므로 서비스를 제공하는 포드의 특정 위치를 알 필요가 없습니다. 이 추상화를 통해 Kubernetes는 서비스에 액세스하는 클라이언트의 기능에 영향을 주지 않고 Pod를 자유롭게 관리(예: 크기 조정, 업데이트 또는 재배치)할 수 있습니다. 포드의 이러한 동적 관리는 시스템의 전반적인 유연성, 확장성 및 안정성을 향상시킵니다.

 

프론트엔드 웹 서버와 백엔드 데이터베이스 서버가 있다고 가정해 봅시다. 프론트엔드 역할을 하는 파드는 여러 개 있을 수 있지만 백엔드 데이터베이스 파드는 하나만 있을 것입니다. 시스템이 기동하려면 두 가지 문제를 해결해야 합니다.

  • 웹 서버가 하나든 수백 개든 상관없이 외부 클라이언트는 프론트엔드 파드에 연결할 수 있습니다.
  • 프론트엔드 파드는 백엔드 데이터베이스에 연결해야 합니다. 데이터베이스는 파드 내에서 실행되므로 시간이 지남에 따라 클러스터 주위를 이동해 IP 주소가 변경될 수 있습니다. 백엔드 데이터베이스가 이동할 때마다 프론트엔드 파드를 재설정하는 것은 쉽지 않습니다.

프론트엔드 파드에 관한 서비스를 만들고 클러스터 외부에서 액세스할 수 있도록 구성하면 외부 클라이언트가 파드에 연결할 수 있는 하나의 고정 IP 주소가 노출됩니다. 마찬가지로 백엔드 파드에 관한 서비스를 생성해 안정적인 주소를 만듭니다. 파드의 IP 주소가 변경되더라도 서비스 IP주소는 변경되지 않습니다. 또한 서비스를 생성하면 프론트엔드 파드에서 환경변수 또는 DNS 이름으로 백엔드 서비스를 쉽게 찾을 수 있습니다.


서비스 생성

서비스를 지원하는 파드가 한 개 혹은 그 이상일 수 있습니다. 서비스 연결은 서비스 뒷단의 모든 파드로 로드밸런싱됩니다. 그러나 정확히 어떤 파드가 서비스의 일부분인지 아닌지를 어떻게 정의할까요?

 

레이블 셀렉터를 이전에 다룬적이 있습니다. 그리고 레플리케이션 컨틀로러와 기타 파드 컨트롤러에서 레이블 셀렉터를 사용해 동일 한 세트에 속하는 파드를 지정하는 방법 또한 다루었었습니다. 다음 그림에 보면 알 수 있듯이 동일한 메커니즘이 서비스에도 그래도 사용됩니다.

 

  1. kubectl expose로 서비스 생성
    서비스를 생성하는 가장 쉬운 방법은 kubectl expose를 사용하는 것입니다. 이전에 이를 사용하여 레플리케이션 컨트롤러를 노출하는데 사용했었습니다. expose 명령어는 레플리케이션 컨트롤러에서 사용된 것과 동일한 파드 셀렉터를 사용해 서비슷리소스를 생성하고 모든 파드를 단일 IP 주소와 포트로 노출합니다.

  2. YAML 디스크립터를 통한 서비스 생성
apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80                    <  서비스가 사용할 포트
    targetPort: 8080       <  서비스가 포워드할 컨테이너 포트
  Selector:
    app: kubia

이 디스크립터에는 kubia라는 서비스를 정의했습니다. 이 서비스는 포트 80의 연결을 허용하고 각 연결을 app=kubia 레이블 셀렉터와 일치하는 파드의 포트 8080으로 라우팅합니다. 이 YMAL을 kubectl create 혹은 kubectl apply로 파일을 실행해 서비스를 생성할 수 있습니다.


서비스 조회 및 테스트

YAML을 게시한 후 네임스페이스의 모든 서비스 리소스를 조회하고 서비스에 내부 클러스터 IP가 할당됐는지 확인할 수 있습니다. 명령어 kubectl get svc(service)를 입력하면 확인할 수 있습니다.

 

이 명령어는 서비스에 할당된 IP 주소를 확인할 수 있고, 이 IP는 클러스터 IP이므로 클러스터 내부에서만 액세스할 수 있습니다. 서비스의 기본 목적은 파드 그룹을 클러스터의 다른 파드에 노출시키는 것이지만 대개 서비스를 하는 이유는외부로 노출하기 위함일 것입니다. 지금은 이 것보다 클러스터 내에서 서비스를 사용해보고 어떻게 동작하는지 살펴보겠습니다.

 

다음은 클러스터 내에서 서비스로 요청을 보낼 수 있는 방법을 조금 정리 했습니다.

  1. 서비스 내에서 클러스터 IP로 요청을 보내고 응답을 로그로 남기는 파드를 만듭니다. 그 후 파드의 로그를 검사해 서비스의 응답이 무엇인지 확인할 수 있습니다.
  2. 쿠버네티스 노드로 ssh 접속하고 curl 명령을 실행할 수 있습니다.
  3. kubectl exec 명령어로 기존 파드에서 curl 명령을 실행할 수 있습니다.

kubectl exec

kubectl exec 명령어를 사용하면 기존 파드의 컨테이너 내에서 원격으로 임의의 명령어를 실행할 수 있습니다. 컨테이너의 내용, 상태, 환경을 검사할 때 유용합니다. kubectl get pods 명령어로 파드를 조회하고 exec 명령어의 대상으로 하나를 선택합니다. 또한 서비스의 클러스터 IP를 알아야합니다. 다음 명령어를 실행할 때는 파드 이름과 서비스 IP를 상황에 맞게 변경해서 사용할 수 있습니다. 이 명령어에 대해서는 이전에 다룬적이 있어 사용하는 방법보다는 작동 방식을 알아보겠습니다. 사용 방법이 궁금하시다면 다음 페지에 간단히 정리되어 있습니다.

 

[Kubernetes] Kubectl 명령어 모음 [2] 수정, 실행, 대기

목차 수정 관련 명령어 kubectl scale kubectl patch kubectl edit kubectl label kubectl annotate 컨테이너에서 명령어 실행 kubectl exec 대기 명령어 kubectl wait 수정 관련 명령어 kubectl scale kubectl scale 명령어는 Kubernete

easyitwanner.tistory.com

 

exec 명령을 실행한 후 이벤트 순서는 다음과 같습니다.

  1. 파드의 컨테이너 내에서 curl 명령을 실행하도록 쿠버네티스에 지시합니다.
  2. curl은 HTTP 요청을 서비스 IP로 보냈습니다. 이 IP에는 파드들이 연결돼 있습니다.
  3. 쿠버네티스 서비스 프록시가 연결을 가로채서 파드들 중 임의의 파드로 요청을 전달합니다.
  4. 해당 파드 내에서 실행중인 Node.js는 요청을 처리하고 해당 파드의 이름을 포함하는 HTTP응답을 반환합니다.
  5. curl은 표준 출력으로 응답을 출력하고 이를 kubectl 이 있는 로컬 시스템의 표준 출력에 다시 표시합니다.

이 방법은 컨테이너 내의 주 프로세스가 서비스와 통신하는 것과 크게 다르지 않습니다.


서비스 세션 어피니티 구성

동일한 명령을 몇 번 더 실행하면 동일한 클라이언트에서 요청하더라도 서비스 프록시가 각 연결을 임의의 파드를 선택해 연결을 다시 전달(forward)하기 때문에 요청할 때마다 다른 파드가 선택됩니다.

 

반면 특정 클라이언트의 모든 요청을 매번 같은 파드로 리디렉션하려면 서비스의 세션어피니티 속성을 기본값 None 대신 ClienIP로 설정합니다.

apiVersion: v1
kind: Service
spec:
  sessionAffinity: ClientIP
...

이로써 서비스 프록시는 동일한 클라이언트 IP의 모든 요청을 동의한 파드로 전달합니다.

 

쿠버네티스는 None과 ClientIP라는 두 가지 유형의 서비스 세션 어피니티만 지원합니다. 쿠키 기반 세션 어피니티 옵션이 없지만 쿠버네티스 서비스가 HTTP 수준에서 작동하지 않는다는 것을 생각해 보면 크게 놀라운 일은 아닙니다. 서비스는 TCP와 UDP 패킷을 처리하고 그들이 가지고 있는 페이로드는 신경 쓰지 않습니다. 쿠키는 HTTP 프로토콜의 구성이기 때문에 서비스는 쿠키를 알지 못하며, 세션 어피니티를 쿠키 기반으로 할 수 없는 이유입니다.


한 서비스로 여러 포트 노출하기

서비스는 단일 포트만 노출하지만 여러 포트를 지원할 수도 있습니다. 예를 들어 파드가 두 개의 포트를 수신한다면 하나의 서비스를 사용해 포트 80과 443을 파드의 포트 8080과 8443으로 전달할 수 있습니다. 이 경우 굳이 두 개의 서비스를 만들 필요가 없습니다. 하나의 서비스를 사용해 멀티 포트 서비스를 사용하면 단일 클러스터 IP로 모든 서비스 포트가 노출됩니다. 하지만 여러 포트가 있는 서비스를 만든다면 각 포트의 이름을 지정해 줘야합니다.

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - name: http
    port: 80                          >  포트 80은 파드의 포트 8080과 매핑됩니다.
    targetPort: 8080
  - name: https
    port: 443                        >  포트 443은 파드의 포트 8443에 매핑됩니다.
    targetPort: 8443
  selector:                           >  레이블 셀렉터는 항상 모든 서비스에 적용됩니다.
    app: kubia

레이블 셀렉터는 서비스 전체에 적용되며 각 포트를 개별적으로 구성할 수는 없습니다. 다른 포트가 다른 파드 서브세트에 매핑되도록 하려면 서비스를 2개 만들어야 합니다.


이름이 지정된 포트 사용

각 파드의 포트에 이름을 지정하고 서비스 스펙에서 이름으로 참조할 수도 있습니다. 따라서 포트 번호가 잘 알려진 경우가 아니더라도 서비스 스펙을 좀 더 명확하게 합니다.

apiVersion: v1
kind: pod
spec:
  containers:
  - name: kubia
    ports:
      - name: http                      >  컨테이너 포트 8080은 http라고 정의 합니다.
        containerPort: 8080
      - name: https                    >  포트 8443은 https라고 정의합니다.
        containerPort: 8443

이렇게 파드를 정의해주면 서비스 스펙에서 이 이름으로 해당 포트를 참조할 수 있습니다.

apiVersion: v1
kind: Service
spec:
  ports:
  - name: http             >  포트 80은 http라는 컨테이너 포트에 매핑됩니다.
    port: 80
    targetPort: http
  - name: https            >  포트 443은 컨테이너 포트의 이름이 https인 것에 매핑됩니다.
    port: 443
    targetPort: https

이렇게 하면 나중에 서비스 스펙을 변경하지 않고도 포트 번호를 변경할 수있다는 큰 장점이 있습니다. 파드는 현재 http라는 이름에 포트 8080을 사용하고 있지만 나중에 포트 80으로 변경하기로 했다고 가정해봅시다. 포트가 번호로 설정되어 있었다면 파드마다 일일이 들어가서 수정해야할 것입니다. 하지만 이름을 지정했다면 이름이 있는 곳만 수정하면 됩니다.

반응형