Spring Cloud Config

이원석·2023년 10월 11일

SpringCloud

목록 보기
2/5
post-thumbnail
본 내용은 인프런의 이도원님의 SpringCloud 강의를 참고하여 작성되었습니다.



0. 시작하며

Spring 프로젝트를 진행하며 서버 포트를 할당, 어플리케이션의 이름, JDBC 리소스의 할당 등을 위해 설정 정보 파일을 사용했었다. 설정 정보 파일에 변경사항이 생길때마다 매번 프로젝트를 다시 빌드하는 과정은 여간 귀찮은게 아니었다.

가끔식 이런 yml 파일들을 관리해주는 중앙 관리서버가 있으면 좋겠다고 생각했는데 이미 있었다!! 게다가 도메인별로 서비스를 분리하는 MSA에서 여러개의 yml 파일들을 관리하거나, 개발 환경에 맞는 별도의 관리가 가능하다는 장점이 있다!



1. Spring Cloud Config란?

Spring Cloud Config란..
분산 시스템에서 서버 클라이언트 구성에 필요한 설정 정보 파일(application.yml)을 내부가 아닌 중앙화 된 외부 시스템에서 관리하기 위한 서비스라고 생각하면 된다.

이러한 환경은 독립적인 서비스로 작동하는 마이크로서비스 아키텍처에서 구성 관리의 효율성을 향상시킬 수 있다.



2. 왜 사용할까?

2-1. 중앙화된 구성 관리

중앙화된 저장소에서 애플리케이션의 구성 정보를 관리가 가능하다. 때문에 구성 정보가 분산되지 않고 중앙에서 관리되며 일관성과 안정성을 확보할 수 있다.


2-2. 다양한 환경에서 구성 관리

다양한 환경(로컬, 개발, 테스트, 스테이징, 프로덕션 등)에 대한 별도의 구성 파일을 관리할 수 있으며, 애플리케이션이 해당 환경에 따라 올바른 구성을 로드할 수 있다.

배포시에는 파이프라인을 통해 DEV-UAT-PROD 환경에 맞는 구성 정보를 선택해 사용할 수 있다.

[배포중인 서비스]
(A, B, C) -> (Spring Cloud Config) - (Priavte Git Repository)


2-3. 런타임중에도 구성 정보 업데이트

보통 설정 정보 파일을 수정하고 다시 적용하기 위해서는 프로젝트를 다시 빌드해야하는 작업이 필요했다.. 귀찮을 뿐만 아니라 IntelliJ + Spring 조합은 메모리도 많이 차지하는 무거운 프로그램이기 때문에 다시 빌드하는 시간이 낭비되기도 한다.

Spring Cloud Config를 활용하면 중앙 저장소에서 필요한 설정 정보 파일을 동적으로 할당하기 때문에 다시 빌드하는 과정이 필요없다!

예를들어,
application.yml 파일에서 token.yml을 분리시켜놓고, token.yml이 수정되었을 때, 해당 서버에서 actuator/refresh 엔드포인트를 POST 요청만 한다면 변경사항이 적용된다!

뿐만 아니라 Spring Cloud Bus를 통해 일괄적인 변경사항 적용이 가능하다.



3. Config Service

Config Service를 구현해보자!

가장 먼저 yml을 관리하는 중앙화 서버가 하나 필요하기 때문에 프로젝트를 생성해주자.

3-1. 의존성 추가

dependencies {
	implementation 'org.springframework.cloud:spring-cloud-config-server'
	...
}

Spring Cloud Config Server 라이브러리를 사용하기 위한 의존성을 추가한다.


3-2. ConfigServer 지정

@SpringBootApplication
@EnableConfigServer
public class ConfigServiceApplication {

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

}

MainClass에 @EnableConfigServer를 사용하여 ConfigServer로 지정한다.


3-3. application.yml (ConfigServer)

yml 파일들을 관리하고 가져오기 위한 방법으로는 3가지가 있다.

  1. 로컬 저장소

     server:
       port: 8888
    
     spring:
       application:
         name: config-service
         
       profiles:
         active: native
         
       cloud:
         config:
           server:
             native:
    		  search-locations: file://${user.home}/Desktop/.. [경로]

    yml 파일들을 로컬 저장소에서 관리하는 방법이다.

  • spring.profiles.active
    특정 프로파일을 설정하면, Config Server는 해당 프로파일과 일치하는 구성 파일을 가져온다. 예를 들어, spring.profiles.active를 dev로 설정하면 application-dev.yml과 같은 dev 프로파일에 해당하는 구성 파일을 가져온다.

    spring.profiles.active를 설정하지 않거나 native 프로파일을 활성화하면, Config Server는 기본적으로 application.yml과 같은 프로파일이 없는 (또는 기본) 구성 파일을 가져온다. (Default)


    하지만 로컬 저장소를 사용하기 위해서는 spring.profile.active를 반드시 native로 설정해주어야 한다! 다른 profile을 사용하려면 native, dev, prod.. 이렇게 추가해야 한다.


  1. Git 저장소

    server:
      port: 8888
    
     spring:
       application:
         name: config-service
    
       cloud:
         config:
           server:
             git:
               uri: https://github.com/~~ 깃허브 주소
               username: ...
               password: ...

    yml 파일들을 원격 Git 저장소에서 관리하는 방법이다. Private Repository의 경우에는 계졍의 id와 accessToken이 필요하다. (아니면 필요없음)

    변경사항은 add, commit, push를 통해 원격 Git 저장소에 저장해야 한다.


  2. Git 로컬 저장소

    server:
      port: 8888
    
     spring:
        application:
           name: config-service
    
        cloud:
          config:
            server:
              git:
                uri: file:///Users/wonseok/... [경로]

    yml 파일들을 로컬 Git 저장소에서 관리하는 방법이다.로컬 디렉토리에서 Git init을 통해 Git 저장소를 초기화해야 한다.

    이후 add, commit, push(X) 을 통해 변경사항을 로컬 저장소에 기록하면 된다.


3-4. 엔드포인트 호출

localhost:8888/설정정보파일이름/profilename 엔드포인트를 통해 ConfigServer에서 yml 파일들에 대한 정보를 가져올 수 있다.

profile이 default인 경우, profile이 지정되지 않은 yml 파일들을 가져온다.


prod profile yml들을 가져왔는데, default profile yml도 같이 조회가 되었다. profile이 지정되지 않은 yml 파일들은 조회시에 무조건 포함되는 것 같다.



4. Ohter Service

이제 다른 서버에서 Config Server를 통해 설정정보 파일을 가져오자.

4-1. 의존성 추가

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-actuator'
	implementation 'org.springframework.cloud:spring-cloud-starter-config'
	...
}

애플리케이션에서 Spring Cloud Config 서버를 통해 구성 정보를 가져오기 위한 Starter, 모니터링을 위한 Actuator 모듈을 추가한다.

  • 구성 관리: Spring Cloud Config를 사용하여 중앙 서버에서 애플리케이션의 구성 정보를 관리하고 업데이트한다. Actuator를 사용하여 구성 정보를 확인, 관리, 런타임 갱신을 할 수 있다.

4-2. application.yml (UserService)

spring:
  cloud:
    config:
      name: bookdodum

  config:
    import: optional:configserver:http://localhost:8888
  
  profiles:
    active: dev


management:
  endpoints:
    web:
      exposure:
        include: refresh

# ConfigServer에서 받아올 Token 정보는 주석처리 
#token:
#  expiration_time: 864000000
#  secret: "my_token"

import할 ConfigServer의 uri와 profile을 지정한다.

설정정보 파일 변경시 런타임 환경에서 실시간으로 적용시키기 위한 actuator의 refresh 엔드포인트를 추가해주자.


4-3. Controller

    @GetMapping("/health_check")
    public String status() {
        return String.format("Token Secret = " + env.getProperty("token.secret") +
                ", Token Expiration Time= " + env.getProperty("token.expiration_time"));
    }

설정정보 파일을 잘 가져오는지 확인하기 위한 엔드포인트를 만들어주자.



health_check 엔드포인트를 호출하면 ConfigServer를 통해 토큰의 정보를 잘 가져온 것을 볼 수 있다.

이번에는 yml 파일을 수정 해보자.


Git 저장소를 예제로 사용하고 있기 때문에 반드시 Git add - commit - push 과정을 통해 변경사항을 스테이징 인덱스에 추가하고 원격 저장소로 동기화 시켜주어야 한다.

actuator의 refresh 엔드포인트를 호출하여 런타임 중에 UserService 애플리케이션의 구성을 다시 로드해야 한다.


다시 조회해보면 변경사항이 잘 적용된 것을 볼 수 있다.



삽질 회고

profile을 지정하며 apigateway에는 prod, user-service에서는 dev yml을 가져오도록 잘못 명시했더니 오류가 발생했다.

왜 그런것일까!! 어떻게 보면 당연하지만 처음이라 생각보다 오랜시간 삽질했다..


  1. my-ip:8000/user-service/signin
    토큰 발급 (secret Key - dev)

  2. 토큰 header에 첨부

  3. my-ip:8000/user-servuce/health-check
    (secret Key - prod)

  4. apigateway의 AuthorizationFilter에서 JWT Token의 Signature(SecretKey) 검증!

apigateway에서는 secret key가 prod로 명시되어 있고, 발급받은 key는 dev로 명시되어 있었기 때문에

apigateway의 AuthorizationHeaderFilter에서 토큰을 검증하는 parseClaimsJws(jwt) 메서드에서 계속 401 오류가 발생했다.

덕분에 Filter가 SecretKey를 통해 Validation을 잘 하고 있다는 것을 몸소 느낄 수 있었지만 앞으로는 이런 실수 하지말자..



마무리

ConfigServer를 통해 설정정보 파일을 개발 환경에 맞추어 관리하고 (profile) Actuator 모듈을 사용하여 프로젝트를 다시 빌드하지 않아도 변경 사항을 적용할 수 있게 되었다.

하지만! 마이크로 서비스의 수가 많아진다면 모든 변경 사항에 대한 수동 작업 또한 많아진다.

Spring Cloud Bus를 사용하여 Configuration의 변경 사항을 연결된 노드(마이크로 서비스들) 에게 전달하는 방식으로 이러한 문제를 해결할 수 있다.

다음 포스팅에서는 Spring Cloud Bus에 대해 알아보자.





참고문헌
Inflearn: Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의자료

0개의 댓글