많은 개발자가 프로퍼티 파일(YAML, JSON, XML)을 사용해서 구성 정보를 저장합니다. 이러한 파일 안에 애플리케이션 구성을 설정하는 것은 간단한 작업이므로 대부분의 개발자는 구성 파일을 소스 제어(있다면)에 추가하고 애플리케이션의 한 부분으로 배포하는 것 이상을 하지 않습니다.
하지만, 만약 여러 서비스가 존재하고 여러 서버에서 동작하는 상황이라면 어떻게 될까요? 수백 개의 마이크로서비스가 많은 인스턴스를 실행하고 있는 클라우드 기반의 애플리케이션을 처리하고 있다면 어떻게 될까요?
세 가지 환경(개발, 테스트, 배포)에 대해 서로 다른 환경 구성이 포함되어 있고 이것이 외부에서 관리되지 않는다면 변경 사항이 있을 때마다 코드 저장소에서 파일을 검색하고, 코드 저장소에서 검색해서 통합 과정(있다면)을 따라 애플리케이션을 재시작해야 합니다.
클라우드 기반 마이크로서비스 개발을 위한 모범 사례로 다음 사항들을 고려해야 합니다.
네 가지 원칙을 확인해 봅시다.
이러한 작업을 적용할 때 명심해야 할 점은 구성 정보를 실제 코드 외부로 분리하기 때문에 외부 의존성이 생깁니다. 이를 관리하고 버전 제어를 해야합니다.
다음은 마이크로서비스의 수명 주기를 보여줍니다.
아래 그림은 CI/CD를 통해 구성 정보들이 어떻게 업데이트 되는지 보여줍니다.
방식을 정리하자면 다음과 같습니다.
책에 있는 내용을 그대로 끌어다가 적었는데, 중요한 내용이라 적어놨습니다.
간단하게 정리하자면,
해당 방식은 전형적인 CI/CD 배포의 일부분을 보여줍니다.
다양한 구현 솔루션을 제시하고 있는데 다음과 같은 솔루션들이 있다고 합니다.
여기서는 스프링 클라우드 구성 서버를 선택하고 그에 대한 장점들을 나열하고 있습니다.
스프링 클라우드 컨피그(Spring Cloud Config) 서버는 스프링 부트로 만든 REST 기반의 애플리케이션입니다.
해당 책에서는 코드와 함께 설명들을 제시하고 있는데, 해당 부분은 생략하고 필요한 개념들만 정리를 하도록 하겠습니다.
우선, 스프링 클라우드 컨피그 서버를 설정하기 위해서 xml 파일을 작성할텐데 중요한 것들이 몇가지 있습니다.
1, 2, 3번의 경우 사실 어느 백엔드 서버에서든 중요한 것이고 4번의 무엇인지 살펴봅시다.
BOM은 프로젝트에서 사용되는 의존성들의 버전을 관리하는데 도움을 줍니다.
추가적으로 부트스트랩(bootstrap) 파일에 대한 설명이 나오는데, 보통 부트라는 단어가 붙은 파일이나 장치들은 맨 처음 실행되는 것으로 해당 파일에서도 그에 맞게 필요한 정보들을 담고 있습니다.
bootstrap.yml
파일을 사용하여 컨피그 서버와 마이크로서비스의 구성 정보를 정의합니다.
해당 파일에 저장되는 중요한 정보들은 다음과 같습니다.
컨피그 서버는 스프링 부트 애플리케이션이고, 해당 애플리케이션은 가동되기 위해서는 진입점이 필요합니다. 이것을 부트클래스로 보면 되고, 다음과 같은 것들이 들어가는 클래스들을 의미합니다.
여기서는 복잡한 외부 저장소를 사용하지 않고, 로컬 파일 시스템을 이용해서 설명을 하고 있습니다. 로컬 파일 시스템을 이용하여 파일에 접근할 때는 classpath:
나 file:
를 이용하여 접근하는 native 프로파일을 사용합니다.
이제 구성 파일 설정에 대해서 설명을 해보자.
앞서 언급했듯이 컨피그 서버는 여러 환경의 구성을 가지고 있을 수 있습니다.
여기에 추가로 스프링 클라우드 컨피그는 모든 것이 계층 구조로 동작합니다.
여기서 말하는 계층 구조는 엄청 거창한 계층 구조라기 보다는 여러 환경에서 공통적으로 적용되는 것들은 모두 적용되도록 하나의 파일에서 정의를 내리면서 추가적으로 변경사항이 생길 때 나눠지는 형태로 일종의 트리 형태로 쪼개지는 계층 구조를 생각하면 됩니다.
이러한 계층 구조는 프로퍼티 파일을 이용하여 정의를 할 수 있습니다.
추가적으로, 마이크로서비스의 경우 도커 컨테이너 위에서 동작합니다. 따라서, 도커 컴포즈에서 정의한 환경 변수를 이용해서 해당 작업을 수행할 수 있다는 점을 기억하면 됩니다.
해당 단원의 앞 절에서는 초기 코드 구축에 대한 설명이 나옵니다. JPA를 사용해서 Repository를 구축하고 이것을 활용하는 코드에 대해서 제시하고 있습니다.
해당 부분은 넘어가겠습니다.
여기서 봐야되는 것은 스프링 부트 애플리케이션에서 지속적으로 구성을 관리하는 방법입니다.
일반적으로 스프링 부트 애플리케이션은 시작할 때만 프로퍼티를 읽기 때문에 컨피그 서버에서 변경된 프로퍼티가 자동으로 애플리케이션에 적용되지는 않습니다.
이것을 위해서 스프링 부트 액추에이터(Spring Boot Actuator)는 @refreshScope
어노테이션을 사용하여 스프링 애플리케이션이 구성 정보를 다시 읽게 만드는 /refresh 엔드포인트에 접근할 수 있게 해줍니다.
스프링 부트 액추에이터는 상태 확인을 위해 마이크로서비스 아키텍처에서 자주 사용되는 것으로 Health Check
도 이 라이브러리를 통해서 수행됩니다.
❗️마이크로서비스 갱신
컨비그 서비스를 사용하여 동적으로 프로퍼티를 변경할 때 주의할 점은 동일한 서비스에 대한 여러 인스턴스가 실행 중일 수 있다는 것입니다.
스프링 클라우드 컨피그 서비스는 변경이 발생할 때 이 서비스를 사용하는 모든 클라이언트에 게시(publish)할 수 있는 스프링 클라우드 버스(Spring Cloud Bus)라는 푸시(push)기반의 매커니즘을 제공합니다.
이것은 별도 미들웨어인RabbitMQ
가 필요합니다.
이 방법은 변경을 감지하는 매우 유용한 수단이지만 모든 스프링 클라우드 컨피그 백엔드가 이 푸시 매커니즘을 지원하는 것은 아닙니다.
따라서, 이 문제를 해결하기 위해서 스프링 클라우드 서비스 디스커버리와 유레카(Eureka)를 사용하여 서비스의 모든 인스턴스를 등록하여 문제를 해결합니다.
마지막으로, 프로퍼티를 외부 저장소인 깃 혹은 볼트에 저장하여 사용하는 방법들이 제시되고 있습니다.
여러 방식을 혼합해서 사용 가능하고 외부 저장소를 이용할 경우에는 프로퍼티에 저장되는 중요 정보들이 노출되지 않도록 암호화/복호화 작업을 수행해야 한다는 점입니다.
외부 저장소에 저장을 할 때는 암호화 작업을 수행하고, 컨피그 서버는 이를 복호화하여 안전하게 클라이언트에게 전달할 수 있습니다.