프로그램/Java

Spring Boot Micro Service Architecture 만들기 (1)

with-RL 2023. 7. 9. 11:05

이 포스트는 Spring Boots와 Netflix Eureka를 이용해서 간단한 MSA (Micro Service Architecture)를 만들어 보는 과정에 대한 설명입니다.

이 과정은 다음 환경에서 구성했습니다.

  • windows 11
  • java 11.0.17
  • Docker Desktop-4.16.3
  • IntelliJ IDEA Community Edition 2022-3.3

1. Gradle 설치

  • Gradle Release에서 gradle을 다운 받습니다. 이 과정에서 사용된 버전은 8.1 버전입니다.
  • 윈도우 탐색기에서 파일은 선택 후 마우스 메뉴 버튼을 누르고 실행되는 팝업메뉴에서 ‘압축 풀기’를 선택합니다.

  • ‘압축(Zip) 폴더 풀기’ 창에서 설치하고자 하는 폴더를 입력한 후 ‘압축 풀기’ 버튼을 눌러 압축을 풉니다.
  • 윈도우 프로그램 검색에서 ‘환경’을 입력하고 검색 결과에서 ‘시스템 환경 변수 편집’을 클릭합니다.

  • ‘시스템 속성’ 창에서 ‘환경 변수’ 버튼을 클릭합니다.

  • ‘환경 변수’ 창에서 ‘Path’를 선택하고 ‘편집’ 버튼을 클릭합니다.

  • 환경 변수 편집’ 창에서 ‘새로 만들기’ 버튼을 클릭 후 입력 창에서 gradle이 설치된 폴더 아래 bin 까지 경로를 입력 후 확인을 놀러 환경 변수를 수정 합니다.

  • 새로운 ‘Power Shell’을 실행하고 ‘gradle’ 명령을 실행했을 때 아래와 같은 결과를 확인하면 정상 설치된 것입니다.
$ gradle

2. my-msa 프로젝트 생성

  • my-msa 프로젝트를 생성하고자 하는 적당한 위치에 폴더를 생성합니다.
  • my-msa 폴더에서 마우스 메뉴 버튼을 누른 후 ‘터미널에서 열기’를 선택합니다.

  • 터미널에서 ‘gradle init’ 명령을 실행합니다.
$ gradle init
  • 옵션은 모두 기본 값 그대로 사용합니다.

  • IntelliJ IDEA를 실행 후 ‘Projects’ >> ‘Open’을 선택 후 프로젝트 폴더를 선택합니다.

  • 다음과 같이 my-msa 프로젝트가 열립니다.

  • build.gradle 파일의 내용을 아래와 같이 편집합니다.
subprojects {
    group = 'com.mymsa'
    version = '1.0.0'

    repositories {
        mavenCentral()
    }
}

3. app-core 프로젝트 생성하기

  • app-core는 여러 프로젝트가 공통으로 사용할 정보를 모아 놓은 프로젝트 입니다. 독립적으로 실행되지 않고 library 형태로 사용됩니다.
  • ‘settings.gradle’ 파일을 다음과 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
rootProject.name = 'my-msa'

include 'app-core'

  • 아래와 같이 app-core 관련 폴더를 만듭니다.
    app-core/src/main/java
    app-core/src/main/resources
    app-core/src/test/java

  • app-core/build.gradle 파일을 만들고 아래와 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.core'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

bootJar {
    enabled = false
}
jar {
    enabled = true
}

tasks.named('test') {
    useJUnitPlatform()
}

  • app-core/src/main/java 폴더 아래 ‘com.mymsa.core’ 패키지를 생성합니다.

  • app-core가 준비가 됐습니다. 이 후 공통으로 사용할 내용은 app-core에서 구현할 예정 입니다.

4. app-eureka 프로젝트 생성하기

  • Eureka는 Netflix에서 개발한 MSA를 위한 로드 벨런싱을 위한 미들웨어 입니다.
  • ‘settings.gradle’ 파일을 다음과 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다
rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'

  • 아래와 같이 app-eureka 관련 폴더를 만듭니다.
    app-eureka/src/main/java
    app-eureka/src/main/resources
    app-eureka/src/test/java

  • app-eureka/build.gradle 파일을 만들고 아래와 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.eureka'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}

  • app-eureka/src/main/resources/application.yml 파일을 만들고 아래와 같이 편집합니다.
spring:
  profiles:
    active: local
  application:
    name: app-eureka

---
# local
server:
  port: 9000

spring:
  config:
    activate:
      on-profile: local

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka

  • app-eureka/src/main/resources/logback-spring.xml 파일을 만들고 아래와 같이 편집합니다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>

  • app-eureka/src/main/java 폴더 아래 ‘com.mymsa.eureka’ 패키지를 생성합니다.
  • ‘com.mymsa.eureka’ 패키지 아래 EurekaApplication 클래스를 생성하고 아래와 같이 편집합니다.
package com.mymsa.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

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

}

  • 툴바의 “Open ‘Run/Debug Edit Configurations’ dialog’ 아이콘을 누른 후 ‘Edit Configurations’를 누릅니다.

  • ‘Run/Debug Configuration’ 창에서 ‘+’ 버튼을 누른 후 ‘Application’ 버튼을 누릅니다.

  • 우측 입력 창에서 ‘Modify options’를 선택하고 뜨는 팝업에서 ‘Add VM options’를 선택합니다.

  • 아래와 같이 입력 후 ‘Ok’ 버튼을 누릅니다.
     Name: EurekaApplication
     module: my-msa.app-eureka.main
     VM options: -Dspring.profiles.active=local
     Main class: com.mymsa.eureka.EurekaApplication

  • 툴바에서 ‘EurekaApplication’을 선택하고 ‘Run’ 버튼을 눌러서 ‘EurekaApplication’을 실행합니다.

  • 브라우저에서 http://localhost:9000/에 접속합니다. 아래와 같은 화면을 볼 수 있습니다.

5. app-gateway 프로젝트 생성하기

  • Gateway는 클라이언트이 요청을 받아 적당한 endPoint로 전달하고 처리결과를 클라이언트에게 전달하는 역할을 수행 합니다.
  • ‘settings.gradle’ 파일을 다음과 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'
include 'app-gateway'

  • 아래와 같이 app-gateway 관련 폴더를 만듭니다.
     app-gateway/src/main/java
     app-gateway/src/main/resources
     app-gateway/src/test/java

  • app-gateway/build.gradle 파일을 만들고 아래와 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.gateway'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':app-core')
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}

  • app-gateway/src/main/resources/application.yml 파일을 만들고 아래와 같이 편집합니다.
spring:
  profiles:
    active: local
  application:
    name: app-gateway
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    gateway:
      routes:
        - id: app-web
          predicates:
            - Path=/app-web/**
          uri: lb://app-web

---
# local
server:
  port: 9001

spring:
  config:
    activate:
      on-profile: local

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9000/eureka/

  • app-gateway/src/main/resources/logback-spring.xml 파일을 만들고 아래와 같이 편집합니다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>

  • app-gateway/src/main/java 폴더 아래 ‘com.mymsa.gateway’ 패키지를 생성합니다.
  • ‘com.mymsa.gateway’ 패키지 아래 GatewayApplication 클래스를 생성하고 아래와 같이 편집합니다.
package com.mymsa.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {

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

}

  • 툴바의 “Open ‘Run/Debug Edit Configurations’ dialog’ 아이콘을 누른 후 ‘Edit Configurations’를 누릅니다.
  • ‘Run/Debug Configuration’ 창에서 ‘+’ 버튼을 누른 후 ‘Application’ 버튼을 누릅니다.

  • 우측 입력 창에서 ‘Modify options’를 선택하고 뜨는 팝업에서 ‘Add VM options’를 선택합니다.

  • 아래와 같이 입력 후 ‘Ok’ 버튼을 누릅니다.
     Name: GatewayApplication
     module: my-msa.app-gateway.main
     VM options: -Dspring.profiles.active=local
     Main class: com.mymsa.gateway.GatewayApplication

  • 툴바에서 ‘GatewayApplication’을 선택하고 ‘Run’ 버튼을 눌러서 ‘GatewayApplication’을 실행합니다. 이때 ‘EurekaApplication’은 이미 실행 중 이어야 합니다.

  • 실행중에 ‘localhost/0:0:0:0:0:0:0:1:27017’에 접속할 수 없다는 오류가 발생할 수 있습니다. 아직 mongodb 환경을 설정하지 않아서 발생하는 오류로 무시해도 됩니다.

  • 브라우저에서 http://localhost:9000/에 접속합니다. 아래와 같이 APP-GATEWAY가 추가된 것을 확인할 수 있습니다.

  • 브라우저에서 http://localhost:9001/app-web/hello에 접속합니다. 아래와 같이 오류가 발생합니다. Gateway가 명령을 전달할 app-web이 실행되지 않았기 때문입니다.

6. app-web 프로젝트 생성하기

  • app-web은 클라이언트이 요청을 받아 처리하는 micro service 프로젝트 입니다. 필요에 따라 여러가지 프로젝트를 생성할 수 있지만, 지금은 간단하게 app-web 하나만 생성 하도록 하겠습니다.
  • ‘settings.gradle’ 파일을 다음과 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'
include 'app-gateway'
include 'app-web'

  • 아래와 같이 app-web 관련 폴더를 만듭니다.
     app-web/src/main/java
     app-web/src/main/resources
     app-web/src/test/java

  • app-web/build.gradle 파일을 만들고 아래와 같이 편집합니다. 그리고 우측에 ‘Load Gradle Changes’ 버튼을 눌러서 변경사항을 프로젝트에 반영합니다.
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.web'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':app-core')
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}

  • app-web/src/main/resources/application.yml 파일을 만들고 아래와 같이 편집합니다.
spring:
  profiles:
    active: local
  application:
    name: app-web

---
# local
server:
  port: 0

spring:
  config:
    activate:
      on-profile: local

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9000/eureka/

  • app-web/src/main/resources/logback-spring.xml 파일을 만들고 아래와 같이 편집합니다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>

  • app-web/src/main/java 폴더 아래 ‘com.mymsa.web’ 패키지를 생성합니다.
  • ‘com.mymsa.web’ 패키지 아래 WebApplication 클래스를 생성하고 아래와 같이 편집합니다.
package com.mymsa.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class WebApplication {

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

}

  • 클라이언트의 요청을 처리하기 위해 ‘com.mymsa.web.controller’ 패키지를 만들고 ‘HelloController’ 클래스를 생성 후 아래와 같이 편집합니다.
package com.mymsa.web.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RequestMapping("/app-web")
@RestController
@Slf4j
public class HelloController {

    @GetMapping("/hello")
    public Mono<String> hello() {
        log.info("hello-request received");
        return Mono.just("Hello: " + System.currentTimeMillis());
    }

}

  • 툴바의 “Open ‘Run/Debug Edit Configurations’ dialog’ 아이콘을 누른 후 ‘Edit Configurations’를 누릅니다.
  • ‘Run/Debug Configuration’ 창에서 ‘+’ 버튼을 누른 후 ‘Application’ 버튼을 누릅니다.
  • 우측 입력 창에서 ‘Modify options’를 선택하고 뜨는 팝업에서 ‘Add VM options’를 선택합니다.
  • 아래와 같이 입력 후 ‘Ok’ 버튼을 누릅니다.
     Name: WebApplication
     module: my-msa.app-web.main
     VM options: -Dspring.profiles.active=local
     Main class: com.mymsa.web.WebApplication

  • 툴바에서 ‘WebApplication’을 선택하고 ‘Run’ 버튼을 눌러서 ‘WebApplication’을 실행합니다. 이때 ‘EurekaApplication’ 및 ‘GatewayApplication’은 이미 실행 중 이어야 합니다.
  • 실행중에 ‘localhost/0:0:0:0:0:0:0:1:27017’에 접속할 수 없다는 오류가 발생할 수 있습니다. 아직 mongodb 환경을 설정하지 않아서 발생하는 오류로 무시해도 됩니다.
  • 브라우저에서 http://localhost:9000/에 접속합니다. 아래와 같이 APP-WEB 추가된 것을 확인할 수 있습니다.

  • 브라우저에서 http://localhost:9001/app-web/hello에 접속합니다. ‘HelloController’가 생성한 응답을 정상적으로 수신한 것을 확인할 수 있습니다.

참고

이 포스트와 관련 포스트 입니다.