[Spring Cloud] Spring Cloud Kubernetes - 기본 개념 및 활용

mrcocoball·2024년 1월 28일
0

Spring Cloud

목록 보기
8/8

해당 포스트는 Spring Cloud에 속한 기술들에 대한 개념과 주요 기술에 대해 알아보고 실무에 적용했었던 내용을 정리하는 포스트입니다.

1. 개요

Spring Cloud와 Kubernetes

Kubernetes가 주목받기 전에 등장한 Spring Cloud 프로젝트는 클라우드 네이티브 어플리케이션 및 MSA에 특화된 기능으로 많이 이용되어왔습니다.

그러나 Kubernetes가 등장하고 Kubernetes에서 제공하는 리소스가 기존에 Spring Cloud 프로젝트에서 지원하던 많은 기능들을 포함하게 되면서 Spring Cloud 기반으로 구성되었던 시스템이 Kubernetes로 옮겨지는 경우가 많았다고 합니다.

Spring Cloud 프로젝트에서 제공하던 기능들을 가진 Kubernetes의 대표적인 리소스는 다음과 같습니다.

  • 서비스 디스커버리 : Kubernetes Service / Ingress
  • 로드 밸런싱 : Kubernetes Service (LoadBalancer)
  • API 게이트웨이 : Kubernetes Service / Ingress
  • 설정 관리 : Kubernetes ConfigMap / Secrets

Spring Cloud 프로젝트에서 제공하던 기능들은 어디까지나 개발자들이 어플리케이션 / 코드를 통해 구현을 했어야 했는데 Kubernetes의 경우 어플리케이션 / 코드가 아닌 인프라에서 이러한 기능들을 지원을 하다보니 개발자들이 보다 더 어플리케이션 / 코드 개발에 집중을 할 수 있게 되었다고 합니다.

하지만 모든 서비스가 Kubernetes에서 돌아간다면 상관이 없겠지만 그렇지 않은 경우도 많고, Spring Cloud에서 지원하는 기능이 보다 더 고도화되어 있는 경우도 있어 순수하게 Kubernetes만으로 Spring Cloud를 대체하는 것보다는 둘을 같이 사용하는 경우가 대부분이라고 합니다.

실제로 NHN은 발표 자료에서 Spring Cloud 기반 서비스를 Kubernetes로 옮기는 과정에서 다음과 같이 변경하였다고 하는데요.
[출처 : https://www.youtube.com/watch?v=otss__0kf-g]

여기서 눈여겨봐야 할 부분이 바로 Spring Cloud Kubernetes 입니다.

Spring Cloud Kubernetes

Spring Cloud Kubernetes는 개발자가 Kubernetes에서 Spring Cloud 어플리케이션을 빌드 / 실행할 수 있도록 Spring Cloud 인터페이스 구현을 제공하는 프로젝트입니다.

Spring Cloud의 기술을 Kubernetes가 가진 리소스를 활용하도록 지원하며, 프로젝트 소개에서는 MSA, Spring Cloud, Kubernetes를 통한 개발을 할 때 필수적인 사항은 아니라고 이야기하고 있습니다.

다만 Kubernetes의 리소스 (Service, Ingress, ConfigMap / Secret 등)가 Spring Cloud의 기능을 어느 정도 대체하고 있었기 때문에 이에 맞게 Spring Cloud의 기능을 최적화 / 지원하는 점이 중요합니다.

주요 기능

공식 문서에서 소개하는 주요 기능은 다음과 같습니다.

  • Kubernetes awareness
    • Spring Cloud 어플리케이션이 Kubernetes 환경에서 동작하는지 여부를 감지
  • DiscoveryClient implementation
    • Kubernetes의 Service를 활용, Spring Cloud의 서비스 디스커버리를 지원
  • PropertySoruce objects configured via ConfigMaps
    • Kubernetes의 ConfigMaps를 활용, Spring Cloud의 설정 서버/클라이언트를 지원
  • Client side loadbalancing via Netflix Ribbon
    • Netflix Ribbon + Kubernetes Service를 통해 클라이언트 사이드 로드 밸런싱 지원

소개를 보시면 감이 오시겠지만 Kubernetes의 리소스를 활용해서 Spring Cloud의 기술을 지원하거나 최적화를 하는 것을 알 수 있는데 이는 곧 Spring Cloud Kubernetes를 제대로 사용하려면 Kubernetes에 대한 배경 지식도 어느 정도 있어야 함을 알 수 있습니다.

따라서 Kubernetes에 대한 어느 정도의 지식 (적어도 리소스의 종류, 동작 방식 등)을 공부하시고 minikube 환경에서 실습을 해보시는 것을 권장합니다.

2. 활용 예시

의존성

보통 Spring 관련 의존성들은 Spring Initializr에서 바로 선택이 가능하지만 Spring Cloud Kubernetes 관련 의존성들은 특이하게 글을 작성하고 있는 2024년 1월 25일 기준으로도 의존성 목록에 없어 직접 공식 문서에서 찾아서 주입을 해줘야 합니다.

또한 공식 문서에 따르면 Kubernetes Java Client에 따라서도 의존성이 달라지는 것으로 보입니다.
저같은 경우 실습 및 실제 프로젝트에서는 Fabric8이 아닌 Kubernetes Java Client의 종속성을 사용하였습니다.

Spring Cloud Kubernetes Discovery Client

implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client'

Spring Cloud Kubernetes Config Client

implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-config'

Spring Cloud Kubernetes Loadbalancer

implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-loadbalancer'

Spring Cloud Kubernetes Discovery Client / Server

Spring Cloud Kubernetes Discovery Client는 Kubernetes용 Discovery Client 구현을 제공하기 위한 클라이언트이며 이를 사용하면 Kubernetes의 Service 엔드포인트를 검색할 수 있습니다.

Spring Cloud Eureka Client와 Eureka Server가 spring.application.name 으로 서비스를 등록 / 검색했다면, Spring Cloud Kubernetes Discovey Client는 서비스를 직접 등록하는 것이 아니라 Kubernetes의 Service 리소스에 등록된 이름이나 엔드포인트를 검색합니다.

# Spring Cloud Eureka Client 사용 시 application.yml에 서비스 이름을 등록, 이를 검색
spring:
  application:
    name: my-service

# Spring Cloud Discovery Client 사용 시 Service 리소스의 name을 검색
apiVersion: v1
kind: Service
metadata:
  name: my-service

사용을 하기 위해선 Spring Cloud Eureka Client와 마찬가지로 메인 클래스에 어노테이션을 부착합니다.

@EnableDiscoveryClient
@SpringBootApplication
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

}

한가지 주의할 점은, Spring Cloud Eureka Client와 Spring Cloud Kubernetes Discovery Client를 같이 사용할 경우 설정이 충돌할 수 있어 Kubernetes를 활용하는 환경이 아니라면 Kubernetes Discovey Client를 비활성화해야 하고 Kubernetes를 활용하는 환경이라면 Eureka Client를 비활성화해야 합니다.

---

spring:
  config:
    activate:
      on-profile: local
  #로컬 환경에서는 Spring Cloud Kubernetes를 사용하지 않는다
  cloud:
    kubernetes:
      config:
        enabled: false
        
#로컬 환경에서는 eureka client를 사용한다
eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
    leaseRenewalIntervalInSeconds: 10
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

---

spring:
  config:
    activate:
      on-profile: dev
  cloud:
    kubernetes:
      discovery:
        all-namespaces: true #모든 네임스페이스에서 활성화

# 개발 환경에서는 eureka client를 비활성화한다
eureka:
  client:
    enabled: false

위의 application.yml에서 알 수 있듯이 spring.cloud.kubernetes.discovery 이하 속성으로 서비스 디스커버리 범위를 지정할 수 있습니다. all-namespaces를 설정한다면 모든 네임스페이스에서 Kubernetes의 서비스를 탐색하며, 그 외엔 원하는 네임스페이스를 설정하려면 spring.cloud.kubernetes.discovey.namespaces[0]=namespace1 이런 식으로 리스트 형태로 작성이 가능합니다. 또한 정규식 형태로 필터링하는 것도 가능합니다.

Spring Cloud Kubernetes Discovery Server도 존재하는데 Spring Cloud Eureka Server가 Eureka Client에서 등록한 서비스 정보를 식별하듯이, Kubernetes 클러스터 내에서 사용 가능한 서비스 정보들을 식별합니다.

Spring Cloud Kubernetes Config Client / Server

Spring Cloud Kubernetes Config Client는 PropertySource를 Kubernetes의 ConfigMap, Secret 리소스에서 가져옵니다.

이 때 application.yml을 다음과 같이 설정할 수 있습니다.

spring:
  config:
    activate:
      on-profile: dev
  cloud:
    kubernetes:
      config:
        sources:
        - name: test-config

config 이하에는 name, namespace 설정을 작성할 수 있고 그 아래의 sources에도 name, namespace 설정을 작성할 수 있으며 sources 아래의 설정이 최우선으로 적용됩니다.

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      config:
        name: default-name
        namespace: default-namespace
        sources:
         # Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
         - name: c1
         # Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
         - namespace: n2
         # Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
         - namespace: n3
           name: c3

분리한 설정은 Kubernetes의 ConfigMap 리소스로 분리할 수 있습니다.

# test-config
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config
data:
  application.yaml: |-
    # application.yml 설정 내용

마찬가지로 Spring Cloud Config Client와 같이 사용할 경우 설정이 충돌할 수 있어 사용하지 않는 쪽을 비활성화해야 합니다.

추가로, Spring Cloud Kubernetes Config Server 역시 존재하는데 Spring Cloud Config Server를 기반으로 ConfigMap, Secret에 대한 환경 저장소를 추가한다고 합니다.

Spring Cloud Kubernetes Loadbalancer

Spring Cloud Kubernetes Loadbalancer는 Kubernetes Service 기반 로드 밸런서 구현을 제공합니다. 아래의 설정을 통해 Kubernetes 서비스 이름을 기반으로 로드 밸런싱할 수 있습니다.

spring:
  cloud:
    kubernetes:
      discovery:
        all-namespaces: true # 모든 네임스페이스에서 탐색
      loadbalancer:
        mode: service # loadbalancer 모드를 Kubernetes 서비스 이름 기반으로 설정

번외 : "system:serviceaccount:default:default" cannot get services in the namespace 오류 발생 시

Spring Cloud Kubernetes Client 사용 시 ServiceAccount + ClusterRole이 필요한데 이게 설정되어 있지 않을 경우 위와 예외가 발생합니다.

이를 막기 위해 Client를 사용하는 Pod의 네임스페이스에 ServiceAccount + ClusterRole을 생성하여야 합니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: fabric8-rbac
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default # pod의 네임스페이스
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Appendix. 출처

https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#why-do-you-need-spring-cloud-kubernetes
https://www.baeldung.com/spring-cloud-kubernetes
https://www.youtube.com/watch?v=otss__0kf-g

profile
Backend Developer

0개의 댓글