본문 바로가기
Framework/Spring Boot

[Spring Boot] Spring Cloud Config: 50개의 서버 설정을 단 한 곳에서 통제하라

반응형

회사가 거대해지면 하나의 거대한 스프링 부트(Spring Boot) 애플리케이션(Monolithic)은 한계를 맞이합니다. 결제팀은 결제 로직만, 회원팀은 회원 로직만 따로 떼어내어 각각 50개의 독립적인 서버로 쪼개는 마이크로서비스 아키텍처(MSA, Microservice Architecture)의 시대가 열립니다. 그런데 이 MSA 환경에서 인프라 엔지니어를 가장 고통스럽게 만드는 것은 코드가 아니라 다름 아닌 application.yml 설정 파일입니다. 공통으로 사용하는 'Redis 서버 IP'가 바뀌거나 '결제 연동 API Key'를 변경해야 할 때, 50개의 프로젝트 레포지토리를 열어서 일일이 yml을 수정하고, 50번의 도커(Docker) 이미지를 다시 굽고, 50대의 서버를 재시작해야 하는 끔찍한 '설정 파편화의 지옥'이 펼쳐집니다. 이 지옥을 끝내기 위해 등장한 구원자가 바로 Spring Cloud Config입니다.

이번 포스팅에서는 "모든 서버의 설정값을 Github라는 단 하나의 금고에 몰아넣고 중앙 통제하는 마법!" Spring Cloud Config Server 구축과 실무 아키텍처에 대하여 다뤄보겠습니다.

☁️ 1. Config Server의 탄생: 코드와 설정의 분리

12-Factor App이라는 최신 클라우드 네이티브 방법론의 제3원칙은 "설정(Config)을 코드(Code)에서 완벽히 분리하라"입니다. 소스코드 안에 DB 비밀번호나 API 키가 하드코딩(또는 로컬 yml에 종속)되어 있으면 보안상 위험할 뿐만 아니라 유연성이 떨어집니다.

Spring Cloud Config 아키텍처는 크게 3가지 구성 요소로 이루어집니다.

  1. Github Repository (저장소): 모든 서비스의 yml 파일들(예: payment-prod.yml, member-dev.yml)을 오직 이 깃허브 레포지토리 한 곳에만 몰아넣고 관리합니다. 변경 이력(History) 추적도 완벽하게 지원됩니다.
  2. Config Server (중앙 서버): 깃허브와 항상 연결되어 있는 특별한 스프링 부트 서버입니다. 클라이언트들의 요청이 오면 깃허브에서 yml을 읽어서 던져주는 다리(Bridge) 역할을 합니다.
  3. Config Client (우리의 서비스들): 결제 서버, 주문 서버 등입니다. 이 녀석들은 부팅될 때 자신의 application.yml 대신, Config Server 주소로 찾아가서 "나 'payment' 서버고 'prod' 환경인데 내 설정값 좀 줘!"라고 부탁합니다.

🛠️ 2. Config Server 초간단 구축하기

Config Server를 띄우는 것은 놀랍도록 쉽습니다. Spring Initializr에서 Config Server 의존성을 추가하고 프로젝트를 생성합니다.

@EnableConfigServer // 🌟 이 어노테이션 하나로 평범한 스프링 부트가 중앙 설정 서버로 진화합니다!
@SpringBootApplication
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

그리고 application.yml에 깃허브 저장소 주소만 꽂아주면 끝납니다.

server:
  port: 8888 # Config Server의 국룰 포트
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/my-company/my-config-repo.git # yml 파일들이 모여있는 깃허브 주소!

🚀 3. Config Client 연동과 대마법 (동적 갱신)

이제 결제(Payment) 서버를 띄워볼 차례입니다. 이 클라이언트는 구동될 때 가장 먼저 Config Server(8888 포트)를 찾아가야 합니다.

# 클라이언트의 application.yml
spring:
  application:
    name: payment-service
  profiles:
    active: prod
  config:
    import: "optional:configserver:http://localhost:8888" # 🌟 나 부팅될 때 일단 저 서버로 가서 설정값 좀 다운로드 받아와 줘!

결제 서버를 실행하면, 로그에 Fetching config from server at : http://localhost:8888 이라는 문구가 찍히며 깃허브에 있던 payment-service-prod.yml의 DB 주소와 설정값들을 기가 막히게 싹 긁어와서 자신의 설정으로 세팅한 뒤 톰캣(Tomcat)을 띄우게 됩니다.

🔥 가장 놀라운 기능: @RefreshScope (재시작 없는 동적 갱신)
클라이언트 코드에 @RefreshScope를 달아두면, 깃허브에서 값을 수정하고 클라이언트의 /actuator/refresh API를 딱 한 번 찌르는 순간! 서버를 재시작하지(Reboot) 않고도 메모리에 올라간 변수값이 실시간으로 싹 바뀌어버립니다. 이벤트 할인율을 10%에서 20%로 무중단으로 실시간 변경할 수 있는 엄청난 무기입니다.


🎯 4. 마무리 및 다음 단계

지금까지 수십 개의 마이크로서비스 설정값을 깃허브 한 곳에 모아 중앙 집중 관리하고, 서버 다운타임(Downtime) 없이 실시간으로 설정값을 갱신(Refresh)해 버리는 웅장한 아키텍처, Spring Cloud Config에 대해 다루어 보았습니다. 이제 인프라 엔지니어의 퇴근 시간이 3시간은 훌쩍 앞당겨졌습니다.

서버 설정은 깔끔해졌는데, MSA 구조의 가장 큰 고통인 '서버 간의 통신(Communication)' 문제가 터졌습니다. 결제 서버가 결제를 완료하면 주문 서버에게 "재고 깎아!"라고 API(HTTP)를 날리는데, 하필 그 순간 주문 서버가 죽어있으면 어떻게 될까요? 결제도 실패하고 다 터져버립니다(강한 결합). 이 치명적인 의존성을 끊어내고, "결제 서버는 메시지를 편지함에 던져놓고 제 갈 길 가고, 주문 서버는 살아나면 언제든 편지를 꺼내 읽어라!"라는 진정한 비동기 이벤트 주도 아키텍처(EDA)가 필요합니다. 이어지는 23단계 포스팅에서는 "마이크로서비스 생태계의 절대적인 대동맥!" Spring Boot와 Apache Kafka(아파치 카프카) 메시지 큐(Message Queue) 연동의 모든 것에 대해 아주 뼈 때리게 파헤쳐 보겠습니다!

반응형