[Spring Cloud] - 1. Configuration Server 구성

지난 글에서 MSA(Micro Service Architecture)에 대한 기본적인 내용에 대해서 알아봤었는데요. 혹시라도 이 글을 읽어보지 못했다면, 아래의 링크를 통해서 직접 읽어보실 수 있습니다.

 

MSA (Micro Service Architecture) 란 무엇일까?

안녕하세요. 오늘은 Micro Service Architecture에 대해 이야기 해보고자 합니다. 한동안 MSA가 굉장히 화두였는데, 요즘은 분위기가 식어지는 듯하여 오늘 블로그에 이 글을 적게 되었습니다. 우리는 백엔드 개발..

blog.neonkid.xyz

이번 파트에서는 Java 언어의 웹 개발 프레임워크인 Spring을 이용해서 이 Micro Service Architecture를 구성하는 시간을 가져보도록 하겠습니다. 그 첫 번째는 바로 Configuration Server를 구성하는 것입니다.

 

Configuration Server의 필요성

웹 서버를 개발할 때 우리는 이 서버의 파라미터를 주기 위해서 Configuration을 설정합니다. Spring의 경우, application.properties 파일을, Flask에서는 env.py, Node.js에서는 package.json 등을 이용하는 것이죠.

그런데, Micro Service Architecture를 구성하려니 Configuration Server를 구성해야 합니다. 우리가 MSA를 사용하는 이유는 서비스를 분산하는 데 있습니다. 비즈니스 로직을 한 서버에 몰아담지 않고, 기능마다 쪼개어 서버를 개발하기 때문에 그에 따른 환경도 다 제각각일 수 있습니다.

하지만 서버를 한 개 개발할 때는 Config를 한 개만 설정하면 되지만 서비스 단위로 쪼개어 개발할 경우에는 그 설정들을 일일이 하나씩 다 잡아줘야 합니다. 굉장히 불편한 일이죠.

그래서 우리는 Configuration Server를 설정할 필요가 있습니다. 각 서비스별로 설정을 다르게 주어주는 것은 그리 어려운 일은 아니지만 이들을 서버별로 개발자가 일일이 손으로 주어주는 것은 손이 많이 필요합니다. 따라서 Configuration Server를 구축하여 각 WAS에서 이를 Pull 하도록 구축하는 것이죠.

Spring Cloud Configuration Example

그림으로 보자면 위와 같은 구성이 됩니다. 메모장과 같은 노트 서비스를 개발한다고 가정했을 때 가장 간단하게 구성할 수 있는 비즈니스 로직으로 회원(Member)과 Note(메모)를 구성한 것입니다. 각 서비스별로 웹 서비스를 별도로 개발하였을 때, 각 설정은 Configuration Server에서 받는 방식인 것이죠.

이렇게 구성해서 얻을 수 있는 또 다른 이점으로는 서버의 중단없이 설정을 바꿀 수 있다는 점입니다. Tomcat이나 JBoss 등으로 WAS를 운영해보신 분들은 느끼시는 것이지만 서버의 구성이 변경되면 서비스가 중단된 상태로 재시작이 됩니다. 서비스의 리스크가 굉장히 크다는 단점과 함께 곤란한 문제 중 한 가지입니다.

 

Configuration Server 만들기

어떻게 구동되는지 구조를 알았으니 이제 직접 만들어보는 시간을 가져보도록 하겠습니다. 이 글에서는 아래의 툴을 사용할 것임을 알려드립니다.

- JetBrains IntelliJ IDEA
- Java 1.8.0
- Gradle

주로 제가 사용하는 프로그래밍 언어와 IDE 도구, 빌드 도구를 선택하였습니다. 

ext {
    set('springCloudVersion', 'Hoxton.SR1')
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-config-server'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

build.gradle에서 Spring Cloud Config Server의 패키지를 받을 수 있도록 위와 같은 설정을 추가합니다.

package xyz.neonkid.configserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

그러고 난 뒤, EnableConfigServer 어노테이션만 붙여주면 기본적인 구성 서버의 틀은 완성입니다. 

# Configuration Server 기본 설정과 프로파일
server:
  port: 9000
spring:
  profiles:
    active: native, local

resources/bootstrap.yml

이제 이 서버가 어느 포트를 사용할지, 그리고, 기본적으로 어디에 있는 구성 파일을 읽을지를 설정해줍니다. 별도의 파라미터가 없을 경우에는 서버 자신의 파일을 읽도록 먼저 구성해줍니다.

# 로컬 파일을 사용할 때의 읽을 파일의 경로.
spring:
  profiles: local
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/server-configs

resources/bootstrap-local.yml

search-locations가 바로 설정 파일들이 있는 경로를 가리킵니다. 이 경로는 Java의 Package 경로, JVM에서 사용하는 환경 변수 모두 사용할 수 있습니다. 예시를 몇 개 들어보면..

* OS X / Linux
   - file://${user.home}/server-configs

* Windows
   - file:///${user.home}/server-configs

이렇게도 사용할 수 있는 것이죠. 만약 서버 내에 구성 파일을 설정하기 까다로워서 심볼릭 링크를 사용하는 등의 방법도 있겠지만 가능한 위의 방법을 쓰는 것이 현명합니다.

 

Config을 Configuration 서버와 붙이기

이제 구성 서버도 완성되었으니 각 서비스별로 설정을 구성하고, 이를 서버에서 동기화 할 수 있도록 구성해봅시다. 위에서 우리는 로컬 환경에 있는 환경 설정을 불러와서 동기화 시키는 방법을 선택했으므로 이 방법을 그대로 사용해보도록 하죠.

spring:
    profiles: dev
    message: Loaded MemberService for Development Mode..

server-configs/member-service-dev.properties

먼저 회원 서비스에 대한 개발 서버의 구성 설정을 나타낸 것입니다. 반대로 배포/운영 서버의 경우, profiles만 다르게 주고 설정할 수도 있습니다.

spring:
    profiles: prod
    message: Loaded MemberService for Production Mode...

server-configs/member-service-prod.properties

음... 그런데, 우리가 기본적으로 Spring Boot 2.0을 사용하여 직접 서버에 환경 설정을 넣었을 때만 해도 properties를 사용했습니다. 그런데, Configuration Server를 사용할 때는 YML 파일 포맷을 사용할 수도 있습니다. 

두 방식의 차이는 설정을 어떻게 구성하느냐에 따라 나누어집니다. 위에서 Properties 파일 포맷을 사용했을 때는 개발 환경과 배포 환경을 서로 다른 환경 설정 파일로 나누어 구성만 가능합니다. 

그러나 YML의 경우, 한 개의 서비스에 모든 환경의 환경 설정을 한 파일에 넣을 수 있습니다. 

spring:
    profiles: dev
    message: Loaded MemberService for Development Mode..
    
---

spring:
    profiles: prod
    message: Loaded MemberService for Production Mode..

server-configs/member-service.yml

개발자마다 차이가 있을 수 있겠지만 설정 파일이 커질 경우, 후자의 방법은 거의 사용되지 않고, 전자의 방식을 사용합니다. 또 후자의 경우, '---' 구분자를 통해서 Spring Cloud Configuration Server가 파싱하여 읽기 때문에 구분자를 반드시 붙여줘야 한다는 점.

위와 같은 방식으로 Note 서비스도 똑같이 만들어주면 끝입니다.

 

Test

자 이제 환경 설정 서버가 만들어졌으니 이제 이를 잘 불러오는지 테스트해보록 하겠습니다. 기본적으로 Configuration Server는 REST API의 GET 메소드를 사용하여 JSON 형태로 환경 설정을 가져오게 됩니다.

따라서 아래의 커맨드를 이용하여 메소드가 잘 동작하는지 확인해보면 됩니다.

 

$ curl http://localhost:9000/member-service/dev | json_pp

OS X / Linux에서 curl 명령어를 사용하여 테스트하게 되면 아래의 결과가 나타납니다.

{
   "profiles" : [
      "local"
   ],
   "version" : null,
   "name" : "member-service",
   "propertySources" : [
      {
         "source" : {
            "spring.message" : "Loaded MemberService for Development Mode..",
            "spring.profiles" : "dev"
         },
         "name" : "file:///home/neonkid/server-configs/member-service-dev.properties"
      }
   ],
   "label" : null,
   "state" : null
}

결과값은 JSON 형태로 출력되며 propertySources 파라미터 값이 위와 같이 나오면 정상적으로 구성 서버가 만들어진 것입니다. 다른 API 또한 위와 같은 형태로 테스트 해 볼 수 있습니다.

 

마치며...

로컬 환경에서 Spring Cloud의 환경 설정 서버를 구성하는 방법에 대해 알아봤습니다. 이 외에도 환경 설정 서버를 구성하는 내용이 더 많이 있지만 이번 글에서는 로컬 환경에 설정 파일을 저장하고, 불러오는 방식으로 마무리를 짓게 되었습니다.

다음 파트에서는 Configuration Server 구성 2번째 주제로 적어보도록 하겠습니다.

 

 

comments powered by Disqus

Tistory Comments 0