반응형

 

 

지난 포스팅에 이어서 여러개의 Service Application으로 구성된 마이크로서비스를 컨테이너 오케스트레이션 도구인 Kubernetes를 사용하여 운영 인프라를 구성하는 방법을 알아볼 예정이다.

 

마이크로서비스 구조에서는 소프트웨어를 작은, 독립적인 서비스 단위로 나누는 방식으로 설계된다. 이러한 독립적인 마이크로서비스는 각각 자체 실행 가능하며, 특정 기능 또는 업무를 처리한다. 다른 마이크로서비스와 통신하여 전체 시스템을 구성하게 된다. 

 

이 때 Kubernetes를 활용하면, 각 마이크로서비스를 독립적으로 배포하고 자동으로 확장(스케일 아웃)할 수 있어, 사용자 요청 증가에 유연하게 대응할 수 있다. 또한, 마이크로서비스의 로드 밸런싱, 자동화된 롤링 업데이트, 장애 복구, 상태 점검(Liveness/Readiness Probe) 등 운영에 필요한 많은 과정을 자동으로 처리해주기 때문에, 복잡한 마이크로서비스 환경을 효율적으로 운영할 수 있다.

 

지난 포스팅에서 Service와 Deployment를 설정하여 애플리케이션 서비스들을 K8s 환경으로 전환했다면, 이번 포스팅에서는 다음 요소를 중심으로 살펴보겠다.

  1. 외부 트래픽을 내부 서비스로 연결하여 URL 기반의 접근을 위한 Ingress 설정
  2. 컨테이너의 상태를 주기적으로 헬스체킹하여 대응할 수 있도록 돕는 Probe 설정

 

목차

Kubernetes의 핵심 리소스 : Pod, Node, Deployment, Service, Ingress, Configmap & Secret & Autoscaler
1. Ingress 설정
2. Probe 설정 
3. 결과 확인

 


Kubernetes의 핵심 리소스

 

 

https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/

 

 

Pod : 컨테이너를 실행하는 최소 단위이며, 독립된 네트워크와 저장소 환경을 가진 논리적 실행 단위이다. 즉 실제 애플리케이션을 실행하는 최소 단위라고 생각할 수 있다.

  1. 오토 스케일링 정책에 의해 하나의 서비스 애플리케이션은  여러개의 Pod로 구성될 수 있다. 
  2. 인스턴스는 정책에 따라서 언제든 삭제되고 새로 생성될 수 있다. 즉 Pod는 일시적인 리소스이기 때문에, Stateless한 애플리케이션 실행 환경을 구성할 수 있도록 설계해야 한다.
  3. 실행 환경 구성 (어떤 애플리케이션 이미지를 실행할지, 어떤 환경 변수를 주입할지 등) 및 Pod의 생성과 소멸 Deployment에 정의된 설정을 기반으로 Kubernetes에 의해 자동으로 관리된다.
  4. Pod를 추가한다는 것은 Kubernetes Cluster를 구성하는 Node들 중 여유가 있는 곳에 새로운 애플리케이션 인스턴스를 띄운다는 의미이다.

 

Node : Kubernetes 클러스터에서 Pod를 실행하는 물리적 또는 가상 머신(서버). 즉 분산 시스템을 이루는 1개의 서버 컴퓨터에 해당한다고 볼 수 있다. 

  1. 만약 Pod를 실행시킬 컴퓨팅 자원이 부족할 경우, 새로운 Node를 Cluster에 편입하여 Pod를 실행할 수 있는 인프라 용량을 확장한다.

 

Deployment : 애플리케이션을 실행하기 위한 Pod의 실행 환경과 생명 주기를 정의하는 리소스이다. 어떤 컨테이너 이미지를 사용할지, 몇 개의 Pod를 유지할지, 롤링 업데이트나 롤백 시 어떤 전략을 사용할지 등을 설정할 수 있다.

  1. Deployment는 내부적으로 Replica Set을 생성 및 관리하며, 지정된 상태를 지속적으로 유지하도록 Kubernetes가 자동으로 조정한다.

 

Service : Pod 집합에 대한 네트워크 접근 경로를 정의하는 리소스이다.

  1. Pod는 생성될 때마다 IP가 바뀔 수 있기 때문에, Service는 Selector를 통해 특정 Pod들을 선택하여, 이들을 하나의 집합으로서 고정된 접근 주소를 할당하고, 그 안의 Pod들에 트래픽을 로드밸런싱하는 기능을 제공한다.
  2. 외부 또는 내부 클라이언트는 Pod의 상태와 무관하게 항상 동일한 주소로 애플리케이션에 접근할 수 있다.

 

Ingress : 클러스터 외부에서 들어오는 HTTP(S) 요청을 내부의 Service로 라우팅하는 규칙을 정의한다.

  1. URL 경로를 비롯한 라우팅 규칙에 따라 다양한 서비스로 요청을 매핑할 수 있으며, TLS 설정이나 인증 처리 등의 프록시 서버의 기능을 수행한다.
  2. 다양한 유형의 Ingress Controller를 사용할 수 있다. 대표적으로는 NginX를 많이 사용한다.

 

ConfigMap & Secret : 컨테이너 환경에서 사용하는 환경 변수를 외부에서 주입하기 위한 리소스. Secret은 민감 정보를 인코딩하여 주입한다.

 

Autoscaler : Pod나 Node의 수를 자동으로 조절하기 위한 오토스케일링 정책을 정의하는 리소스.

  • HPA(Horizontal Pod Autoscaler) : Pod 수를 조절하는 정책. 메트릭 기준(CPU, 메모리 등)을 설정할 수 있다.
  • VPA(Vertical Pod Autoscaler) : Pod 리소스 (CPU/Memory 양)을 조절하는 정책. 
  • Cluster Autoscaler : 클러스터에 있는 Node(서버)의 수를 조절하는 정책

 


 

지난 포스팅에서 Deployment와 Service를 정의하여 5개의 마이크로서비스에 대한 기본적인 실행 환경을 구성했었다. 이제는 마이크로서비스를 외부에 노출하고 운영 안정성을 보완하기 위해서 다음 사항들을 수행할 것이다. 

  • 외부 트래픽을 내부 5개의 마이크로서비스로 연결 및 URL 규칙을 정의하여 트래픽 라우팅을 수행하는 Ingress 설정
  • 마이크로서비스의 상태를 주기적으로 헬스체킹하여 대응할 수 있도록 돕는 Probe 설정

 

 Kubernetes의 기본 환경 구성과 Service & Deployment 리소스 정의 과정을 다루었던 이전 포스팅에서 이어지는 내용이기 때문에 다음 포스팅을 함께 보면 좋을  것 같다.

 

 

<함께 보기> [Kubernetes] 마이크로서비스 배포 (1) : 개요 및 리소스 구성 : Deployment & Service

https://sjh9708.tistory.com/276

 

[Kubernetes] 마이크로서비스 배포 (1) : 개요 및 리소스 구성 : Deployment & Service

이번 포스팅 시리즈에서는 여러개의 Service Application으로 구성된 마이크로서비스를 컨테이너 오케스트레이션 도구인 Kubernetes를 사용하여 운영 인프라를 구성하는 방법을 알아볼 예정이다. 마이

sjh9708.tistory.com

 

 

 

 


1. Ingress 설정

 

Ingress는 Kubernetes 클러스터 외부에서 들어오는 HTTP 요청을 각 마이크로서비스(Service)로 라우팅해주는 역할을 한다.

즉 프록시 서버와 같은 단일 진입점 역할을 하며, URL 경로 기반으로 요청을 마이크로서비스(/core, /booking, /payment 등)으로 전달하도록 설정할 것이다.

외부에서는 단일 도메인으로 접속하되, 클러스터 내부에서는 여러 마이크로서비스가 독립적으로 동작할 수 있도록 구성하는 것이다.

 

 

Ingress 리소스 또한 Deployment나 Service와 마찬가지로 YAML을 통해서 정의하여 클러스터에 업데이트하는 방식으로 사용된다.

 

 

▶ ingress.yaml

apiVersion: networking.k8s.io/v1  # Ingress는 네트워크 관련 리소스이므로 networking.k8s.io/v1 API 그룹을 사용
kind: Ingress                     # 이 리소스는 Ingress (외부 HTTP 요청을 내부 서비스로 연결해줌)
metadata:
  name: trusticket-ingress       # Ingress 리소스의 이름 (kubectl get ingress 등에서 사용됨)

spec:
  ingressClassName: nginx  # Ingress Controller의 이름. 기본적으로 nginx ingress controller가 많이 사용됨
  rules:  # 여러 host, 여러 path에 대한 라우팅 규칙을 정의하는 곳
    - host: kubernetes.docker.internal  # 사용자가 브라우저에서 접속할 도메인 이름 
      http:
        paths:  # 이 host로 들어온 요청 중 어떤 path로 들어왔는지를 기준으로 라우팅
          - path: /core
            pathType: Prefix
            backend:
              service:
                name: tt-core-service  
                port:
                  number: 18080        # 서비스가 노출하는 포트 번호
          - path: /payment
            pathType: Prefix
            backend:
              service:
                name: tt-payment-service  
                port:
                  number: 18081
          - path: /booking
            pathType: Prefix
            backend:
              service:
                name: tt-booking-service  
                port:
                  number: 18082
          - path: /content
            pathType: Prefix
            backend:
              service:
                name: tt-content-service  
                port:
                  number: 18083
          - path: /resources
            pathType: Prefix
            backend:
              service:
                name: tt-resources-service  
                port:
                  number: 18084
  1. apiVersion : 리소스가 속한 k8s API 그룹과 버전을 명시.
  2. kind: YAML이 정의하는 리소스의 종류 (Deployment) 
  3. metadata : 리소스의 이름, 네임스페이스, 라벨 등 식별 정보를 설정하는 영역
  4. spec : Ingress의 핵심 정의 영역. 외부 요청을 내부 서비스로 라우팅하는 규칙을 명시
    • ingressClassName : 사용할 Ingress Controller를 지정.
    • rules : Host 및 Path에 따른 라우팅 규칙 정의
      • host : 요청을 처리할 도메인 이름 
      • paths : 도메인 아래 경로에 대한 라우팅 규칙
        • path : 요청 경로 접두사
        • pathType : Prefix 설정 시 지정한 경로로 시작하는 모든 요청에 적용
        • backend : 연결할 내부 서비스 정보
          • service.name : 대상 서비스의 이름
          • service.port.number : 대상 서비스가 노출한 포트 번호

 


Host

host: kubernetes.docker.internal
  • Ingress는 가상 호스트 기반(Virtual Host Based) 라우팅을 하므로 호스트 도메인을 지정하여 이를 기반으로 동작한다. (IP만으로는 다중 서비스 간의 명확한 분리가 어렵기 때문이다.)
  • 실서비스에서는 도메인을 DNS에 등록하고 이를 Ingress Controller의 외부 IP에 매핑해서 사용해야 한다.
  • 로컬 환경에서는 루프백 도메인(자기 자신(localhost)을 가리키도록 하는 도메인)을 DNS에 등록하고 이를 Ingress Controller에 매핑하여 사용한다.
  • Docker Desktop에서는 기본적으로 kubernetes.docker.internal이라는 루프백 도메인을 제공한다.

 

 

kubernetes.docker.internal은 Docker Desktop의 로컬 테스트용 도메인이다.

 

 

 

 


IngressClass

 

ingressClassName: nginx

Ingress 리소스는 외부 트래픽을 적절한 Service로 매핑하는 Reverse Proxy + Load Balancing하는 역할을 담당한다. 이 때 사용될 방식(클래스)를 지정할 수 있는데 이것이 IngressClass를 지정하는 것이다.

  • 종류: 보통 Nginx, Traefik, HAProxy 등을 많이 사용한다. 포스팅에서는 NginX를 사용하였다.

 

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/cloud/deploy.yaml
kubectl get pods -n ingress-nginx
kubectl get service -n ingress-nginx
kubectl get ingressclass

Ingress 클래스는 클러스터에 별도 설치되어야 작동한다. 따라서 NginX Ingress Class를 사용하기 위해서는 다음 명령어 수행을 통해서 설치 수행 및 완료 확인을 하자.

 

 

 

 

 


Path

paths:  # 이 host로 들어온 요청 중 어떤 path로 들어왔는지를 기준으로 라우팅
  - path: /core
    pathType: Prefix
    backend:
      service:
        name: tt-core-service  
        port:
          number: 18080        # 서비스가 노출하는 포트 번호
  - path: /payment
    pathType: Prefix
    backend:
      service:
        name: tt-payment-service  
        port:
          number: 18081

paths 항목은 Kubernetes의 Ingress 리소스에서 핵심적인 라우팅 규칙을 정의하는 영역이다. 외부에서 들어온 HTTP 요청의 경로(path)에따라 내부의 Kubernetes Service로 트래픽을 전달하는 규칙을 정의할 수 있다. 위의 YAML은 아래와 같은 라우팅 규칙을 정의한다.

 

요청 경로 대상 서비스 서비스에 전달되는 URL
/core/** tt-core-service /core/**
/payment/** tt-payment-service /payment/**

 

 

 


▶ ingress.yaml

apiVersion: networking.k8s.io/v1 
kind: Ingress                     

metadata:
  name: trusticket-ingress       
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2 # URL Rewrite를 위한 Annotation

spec:
  ingressClassName: nginx  
  rules:  
    - host: kubernetes.docker.internal  
      http:
        paths:  
          - path: /core(/|$)(.*) # Rewrite를 위한 정규식
            pathType: Prefix
            backend:
              service:
                name: tt-core-service  
                port:
                  number: 18080        
          - path: /payment(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: tt-payment-service  
                port:
                  number: 18081
          # ...

NginX 등의 프록시 서버의 기능과 유사하게 Ingress 리소스도 URL Rewrite 기능을 활용하여, 외부 요청 경로를 내부 서비스에 전달될 때 경로를 Rewrite(변환)할 수 있다.

  • annotation 지정 : Nginx Ingress Controller의 Rewrite Target을 지정하여 경로 재작성을 지시하였다. 원래 URL 경로 중 일부를 잘라내어 새로운 경로로 재작성하는 것을 의미한다.
    • Rewrite Target으로 사용하는 $2는 (.*)에 해당하는 캡처 그룹을 의미한다.
  • /core(/|$)(.*) : 경로에는 Rewrite를 위해서 정규식을 지정할 수 있다.
    • (/|$)는 첫 번째 캡처 그룹($1)으로 매핑되며, / 또는 끝이 올 수 있다는 뜻이다.
    • (.*)는 두 번째 캡처 그룹($2)으로 매핑되며, 어떤 경로도 올 수 있다는 뜻이다.

 

 

즉 위의 YAML은 첫 번째 경로를 제거한 뒤, 나머지 하위 경로만을 내부 서비스로 전달한다 

요청 경로 대상 서비스 서비스에 전달되는 URL
/core/** tt-core-service /**
/payment/** tt-payment-service /**

 

 

 


 

 

 


2. Probe 설정

 

Kubernetes의 Probe는 애플리케이션의 상태를 주기적으로 점검하여, 서비스가 정상적으로 동작하고 있는지를 판단하기 위한 헬스체크 메커니즘이다.

  • Liveness Probe: 컨테이너가 살아있는지 판단하여(Health Check), 실패 시 자동으로 컨테이너를 재시작한다.
  • Readiness Probe: 컨테이너가 정상적으로 요청을 처리할 준비가 되었는지를 판단하여, 준비되지 않은 경우 Service나 Ingress가 해당 파드로 트래픽을 보내지 않도록 제어한다.

Ingress는 외부에서 들어온 요청을 내부 서비스로 전달하는 역할을 하기 때문에, 서비스가 배포 중이거나 초기화 중인 상황에서 Ingress가 트래픽을 보내버리면 오류 응답이나 예기치 않은 동작이 발생할 수 있다.

따라서 Probe 설정을 통해서 준비되지 않은 Pod나 정상적이지 않은 Pod에는 Ingress가 트래픽을 라우팅하지 않도록 방지할 수 있다.

 

 

 

 

 


▶ tt-core-service-deployment.yaml

apiVersion: apps/v1  
kind: Deployment    
metadata:
  name: tt-core-service  
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: tt-core-service 
  template:  
    metadata:
      labels:
        app: tt-core-service  
    spec:
      containers:
        - image: sjh9708/trusticket-core-service:latest 
          name: tt-core-service  
          env:
          # ...
          # Libeness Probe 설정
          livenessProbe:
            httpGet:
              path: /core/actuator/health
              port: 8080
            initialDelaySeconds: 300
            periodSeconds: 10
            timeoutSeconds: 5
          # Readiness Probe 설정
          readinessProbe:
            httpGet:
              path: /core/actuator/health
              port: 8080
            initialDelaySeconds: 300
            periodSeconds: 10
            timeoutSeconds: 5
      restartPolicy: Always

Probe는 Deployment 리소스 내 컨테이너 설정에 함께 정의하며, HTTP, TCP, Command 방식으로 구성할 수 있다.

  • httpGet : HTTP 방식으로 특정 엔드포인트에 요청을 보내 Health Check를 수행하는 방식이다. Spring Boot 기반 애플리케이션이라면 /actuator/health 같은 엔드포인트를 활용한 HTTP Probe 구성이 자주 사용된다.
  • initialDelaySeconds : 애플리케이션 초기 실행 시의 딜레이를 감안하여 Health Check를 유보하는 시간이다. 즉 애플리케이션이 세팅이 완료된 이후에만 Heal Check를 수행하기 위해서 설정한다.
  • periodSeconds : 헬스 체크의 간격을 지정한다.
  • timeoutSeconds : HTTP 요청의 타임아웃 시간을 지정하여 해당 시간 내에 응답이 오지 않으면 실패로 간주한다.

 

 

 

 

 


3. 결과 확인

 

kubectl apply -f ./configmap.yaml
kubectl apply -f ./secret.yaml

kubectl apply -f ./booking-service/tt-booking-service-deployment.yaml
kubectl apply -f ./booking-service/tt-booking-service-service.yaml

kubectl apply -f ./content-service/tt-content-service-deployment.yaml
kubectl apply -f ./content-service/tt-content-service-service.yaml

kubectl apply -f ./core-service/tt-core-service-deployment.yaml
kubectl apply -f ./core-service/tt-core-service-service.yaml

kubectl apply -f ./payment-service/tt-payment-service-deployment.yaml
kubectl apply -f ./payment-service/tt-payment-service-service.yaml

kubectl apply -f ./resources-service/tt-resources-service-deployment.yaml
kubectl apply -f ./resources-service/tt-resources-service-service.yaml

kubectl apply -f ./ingress.yaml

kubectl apply 명령어를 통해서 지금까지 작성한 Deployment, Service, Ingress를 포함한 리소스들을 클러스터에 업데이트시켜주자.

 

 

 

 


kubectl get ingress
kubectl describe ingress

Ingress 리소스를 정의한 후, kubectl describe ingress 명령어를 통해 실제 경로 매핑이 어떻게 구성되어 있는지 확인할 수 있다. 

  • trusticket-ingress는 NginX Ingress Class를 사용하고 있다.
  • kubernetes.docker.internal이라는 도메인 기준으로, 각 URL 경로(/core, /payment, /booking, /content, /resources)가 각각의 서비스로 연결되어 있다. 즉 경로가 내부 클러스터 IP로 매핑된 것을 통해 정상적으로 동작 중임을 확인할 수 있다.

 

 

 

 

호스트 Address를 통해 Core Service에 브라우저 상에서 접근하는 것이 성공했다.

 

 

 


Probe 확인

 

kubectl get pods

Health Check의 성공 및 실패 여부에 따라서 Pod의 상태가 변화한다. 위의 그림에서는 Pods가 모두 정상적으로 작동하고 있는 것을 확인할 수 있다. 

 

애플리케이션 초기 구동 시 

  • initialDelaySeconds 시간 이후부터 헬스체크가 시작되며, 그 동안 READY 상태가 0/1로 표시된다.
  • 컨테이너가 계속 유지되고 있다면 STATUS는 Running으로 유지된다.

readinessProbe 실패 시

  • READY 상태가 0/1로 표시된다. STATUS는 계속 Running으로 유지된다.
  • Service는 해당 Pod로 트래픽을 보내지 않게 된다. 즉 Pod는 계속 살아 있으나, 외부 접근 또는 Ingress 라우팅 대상에서 제외된다.

livenessProbe 실패 시

  • Kubernetes는 해당 컨테이너를 강제 재시작한다. 이 과정에서 일시적으로 STATUS가 CrashLoopBackOff 또는 Restarting이 될 수 있다.

 

kubectl describe <POD_NAME>

만약 특정 Pod에서 Probe가 실패했다면 Pods를 Describe했을 때 다음과 같은 내용을 확인할 수 있다. 위와 같은 케이스는 initialDelaySeconds를 너무 짧게 주어서 헬스체크에 실패했을 때 발생했던 이벤트 로그이다.

 

 

 

 

 


정리

 

이번 포스팅에서는 Kubernetes 환경에서 마이크로서비스로 들어오는 외부 트래픽을 내부 서비스로 연결해주는 Ingress 리소스를 설정하고, 각 서비스의 안정적인 운영을 위한 Liveness, Readiness Probe를 구성해보았다.

Ingress는 단일 진입점을 통해 경로 기반으로 요청을 각 서비스에 분산시킬 수 있도록 해주며, 외부 사용자가 서비스에 접근할 수 있는 구조를 제공한다.

또한 Probe 설정을 통해 컨테이너의 상태를 주기적으로 점검함으로써, 죽어있는 파드로 트래픽이 전달되지 않도록 차단하고, 장애를 조기에 감지할 수 있는 기반을 마련하였다.

다음 포스팅에서는 서비스 부하에 따라 파드 수를 자동으로 조절하는 Horizontal Pod Autoscaler(HPA) 설정을 통한 오토스케일링 구성 방법에 대해 알아보겠다.

 


<함께 보기>

 

[Kubernetes] 마이크로서비스 배포 (3) : 오토 스케일링(HPA) 설정

https://sjh9708.tistory.com/278

 

[Kubernetes] 마이크로서비스 배포 (3) : 오토 스케일링(HPA) 설정

지난 포스팅에 이어서 여러개의 Service Application으로 구성된 마이크로서비스를 컨테이너 오케스트레이션 도구인 Kubernetes를 사용하여 운영 인프라를 구성하는 방법을 알아볼 예정이다. 마이크로

sjh9708.tistory.com

 

 

 

 

 

반응형

BELATED ARTICLES

more