공대생 정리노트

5장 : 서비스 본문

Kubernetes/Kubernetes in ACTION

5장 : 서비스

woojinger 2021. 1. 4. 23:18

서비스 사용 이유

 

  • 파드는 일시적이다
  • 노드에 파드를 스케줄링 할 때 파드가 시작하기 직전에 파드의 IP 주소 할당
  • 수평 스케일링은 여러 파드가 동일한 서비스를 제공함. 각 파드는 고유한 IP 주소가 있지만 클라이언트는 그것에 상관이 없어야 하므로 단일 IP 주소로 액세스 할 수 있어야 한다

서비스 활용 예

서비스 생성

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80 # port used by service
    targetPort: 8080 # container port to be forwarded by service
  selector:
    app: kubia

app=kubia 레이블에 있는 pod가 서비스에 포함된다. 포트 80 연결을 허용하고 각 연결을 서비스에 포함된 포트의 8080으로 라우팅한다.

동일한 클라이언트에서 요청하더라도 서비스 프록시가 각 연결을 임의로 파드를 선택해 forward하기 때문에 요청할 때마다 다른 파드가 선택된다.

targetPort의 경우 pod yaml에서 port의 이름을 지정했다면 port의 이름을 참조 할 수 있다.

예를 들어 pod가 containerPort 8080을 http로 이름을 지었다면 위의 yaml에서 targetPort: http로 참조할 수 있다.

서비스 어피니티

특정 클라이언트의 모든 요청을 매번 같은 파드로 리다이렉션 하려면 sessionAffinity의 속성을 ClientIP로 설정해야 한다.

동일한 서비스에서 여러 개의 포트 노출

멀티포트는 다음과 같이 설정할 수 있다.

...
ports:
- name: http
  port: 80
  targetPort: 8080
- name: https
  port: 443
  targetPort: 8443
...

서비스 검색

클라이언트 파드가 서비스의 IP와 포트를 어떻게 알 수 있을까?

환경변수를 통한 서비스 검색

레플리케이션컨트롤러에서 파드를 만들었을 경우 kubectl exec (파드 이름) env로 컨테이너 내부에서 환경 변수를 조회할 수 있다.

환경변수를 보면 서비스의 클러스터 IP와 서비스가 제공하는 포트를 볼 수 있다. 여기서는 KUBIA_SERVICE_HOST와 KUBIA_SERVICE_PORT이다. 

DNS를 통한 서비스 검색

kubectl-system 네임스페이스에는 dns 서버를 실행하는 파드가 있다.

kube-dns-~가 보인다

이 파드는 DNS 서버를 실행해 클러스터에서 실행 중인 다른 모든 파드가 이를 자동으로 사용하게 구성된다. 파드에서 실행 중인 프로세스에서 수행된 모든 DNS 쿼리는 시스템에서 실행 중인 모든 서비스를 알고 있는 쿠버네티스 자체 DNS 서버로 처리된다.

각 서비스는 내부 DNS 서버에서 DNS 항목을 가져오고 서비스 이름을 알고 있는 클라이언트 파드는 FQDN(정규화된 도메인 이름)으로 액세스 할 수 있다.

클러스터 외부에 있는 서비스 연결

서비스가 클러스터 내에 있는 파드로 연결을 전달하는 게 아니라 외부 IP와 포트로 전달하는 경우이다.

 

서비스는 파드에 직접 연결되지 않는다. 엔드포인트 리소스가 그 사이에 있다. 엔드포인트 리소스는 서비스로 노출되는 파드의 IP 주소와 포트 목록이다. 

파드 셀렉터는 IP와 포트 목록을 작성하는 데 사용되고 엔드포인트 리소스에 저장된다. 클라이언트가 서비스에 연결하면 서비스 프록시는 이들 중 하나의 IP와 포트 쌍을 선택하고 들어온 연결을 대상 파드의 수신 대기 서버로 전달한다.

파드 셀렉터가 없다면 수동으로 엔드포인트를 구성해야 한다. 엔드포인트는 별도의 리소스이기 때문에 YAML로 만들 수 있다.

엔드포인트를 수동으로 구성하거나 service의 spec에 externalName 속성을 만들어 외부 서비스를 참조할 수 있다.

외부 클라이언트에 서비스 노출

노드포트로 서비스 유형 설정

각 클러스터 노드는 노드 자체에서 포트를 열고 해당 포트로 연결된 트래픽을 서비스로 전달.

 

모든 노트에 특정 포트를 할당하고(모든 노드에서 동일 포트 사용) 서비스를 구성하는 파드로 들어오는 연결 전달

노드포트로 서비스에 엑세스하려면 해당 노드포트에 대한 외부 연결을 허용하도록 해야한다.

외부 로드밸런서로 서비스 노출

노드포트 서비스의 경우 클라이언트가 한 노드에만 요청하면 해당 노드가 장애가 날 때 서비스에 access할 수 없다.

로드밸런서는 공개적으로 access 가능한 고유한 IP 주소를 가지며 모든 연결을 서비스로 전달한다.

로드밸런서는 노드포트 서비스의 확장이다.

불필요한 network hop

노드포트와 로드밸런서의 경우 임의로 선택된 파드가 연결을 수신한 동일한 노드에서 실행 중일 수도 있고 그렇지 않을 수도 있다. 따라서 파드에 도달하려면 추가적인 network hop이 필요할 수도 있다.

수신한 노드에서 실행중인 파드로만 외부 트래픽을 전달하도록 서비스를 구성하면 이 hop을 방지할 수 있다. 이는 externalTrafficPolicy 필드를 설정해야 한다.

이때 로드밸런서가 파드가 있는 노드에만 연결을 전달하도록 해야한다.

단점으로는 모든 파드에 연결이 균등하게 분산이 되지 않을 수 있다.

클라이언트 IP를 볼 수 없다

노드포트로 연결을 수신하면 패킷에서 소스 네트워크 주소 변환(SNAT)가 수행되어 패킷의 소스 IP가 변경된다. 이로 인해 실제 클라이언트 IP를 볼 수 없어 일부 애플리케이션에서 문제가 되기도 한다.

인그레스 리소스로 서비스 외부 노출

 Ingress : 들어가거나 들어가는 행위, 들어갈 권리, 진입로

인그레스는 한 IP 주소로 수십 개의 서비스에 접근이 가능하도록 지원해준다.

HTTP 요청을 인그레스한테 보내면 호스트와 경로에따라 요청을 전달할 서비스가 결정된다.

동작 방식은 다음과 같다.

1. 클라이언트가 /kubia DNS 조회를 수행하고 DNS 서버는 인그레스 컨트롤러의 IP를 반환한다.

2. 클라이언트는 HTTP 요청을 인그레스 컨트롤러로 전송하고 host 헤더에서 /kubia를 지정한다.

3. 컨트롤러가 헤더에서 액세스하려는 서비스 결정해서 해당 서비스와 관련된 엔드포인트 오브젝트로 파드 IP조회해 클라이언트 요청을 파드로 전달한다.

레디니스 프로브

새로 만들어진 파드가 레이블로 인해 서비스의 일부가 되었지만 요청을 처리할 준비가 안되면 어떨까? 이러한 경우 readiness probe를 정의해 특정 파드가 클라이언트 요청을 수신할 수 있을지 결정한다.

readiness probe는 주기적으로 호출된다. 종류는 다음과 같이 3가지가 있다.

  • 프로세스를 실행하는 Exec 프로브
  • HTTP GET 프로브
  • TCP 소켓 프로브

readiness probe는 항상 정의하는 것이 좋다.

 

liveness probe vs readiness probe

liveness probe는 상태가 좋지 않은 컨테이너를 교체해 파드의 상태를 정상으로 유지

readiness probe는 요청을 처리할 준비가 된 파드의 컨테이너만 요청을 받게 한다.

readiness probe가 실패하면 파드는 엔드포인트 오브젝트에서 제거된다. 

헤드리스 서비스

  • 클라이언트가 모든 파드에 연결해야 하는 경우
  • 파드가 다른 파드에 각각 연결해야 하는 경우

이 경우 서비스로 연결하지 말고 각 파드의 IP 주소 목록을 알아야 한다.

서비스 스펙의 clusterIP 필드를 None으로 설정하면 쿠버네티스는 클라이언트가 서비스의 파드를 연결할 수 있는 클러스터 IP를 할당하지 않기 때문에 서비스가 헤드리스가 된다. 이 경우 DNS 서버에 요청을 하게 되면 해당 서비스에 대한 여러 개의 레코드들을 반환하게 된다.

 

Comments