Spring Boot 멀티모듈 아키텍쳐에서 JIB 적용기

아이스__아메리·2023년 7월 17일
1

도입기&적용기

목록 보기
2/7
post-custom-banner

프로젝트 버전

Spring Boot - 2.7.12

Gradle 7.5.1

JAVA - 17

build.gradle

// 플러그인 설치
plugins {
    id 'com.google.cloud.tools.jib' version '3.1.4'
}
allprojects {
		// 플러그인 적용
    apply plugin: 'com.google.cloud.tools.jib'

		// 
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_11

    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
}

targetCompatibility 만 11인 이유는 JIB의 베이스 자바가 11버전이기 때문이다. 오류코드들을 수정하다보니 성공된 버전이다

빌드되는 profile을 위한 분기 처리

ext {
    serverEnv = System.getProperty('server.env', 'dev')
    springBootVersion = '2.7.12'
}
project(':module-api') {
    jib {
        if (serverEnv == 'dev') {
            from {
                image = 'openjdk:17.0.2-slim'
                platforms {
                    platform {
                        architecture = "arm64"
                        os = "linux"
                    }
                }
            }
            to {
                image = 'test/test-api'
                tags = ['0.2.6-dev','latest']
            }
            container {
								// 메인 클래스를 명시적으로 지정 module-api에서 이동해야 인식이됨
                mainClass = 'com.example.ApiApplication' 

                jvmFlags = [
                        '-Dspring.profiles.active=dev',
                        '-Dfile.encoding=UTF-8',
                ]
                ports = ['8080']

								// Jib이 보안이 적용되지 않은 Docker 레지스트리와의 통신을 허용함
                allowInsecureRegistries = true 
            }
        }
    }

    dependencies {
        {... 관련 모듈 및 라이브러리 추가}
    }
}
  • profile이 늘어나게 될 경우 if문 상위에 공통부분으로 엮으면 된다.

실행하는 모듈에서 build

$ gradle jib -Dserver.env=dev

문제해결

#1 Root Directory에서 JIB 실행 시

$ ./gradlew jib

> Task :jib FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':jib'.
> Missing target image parameter, perhaps you should add a 'jib.to.image' configuration parameter to your build.gradle or set the parameter via the commandline (e.g. 'gradle jib --image <your image name>').

#2 Root Directory에서 image parameter를 추가했을 경우

$ gradle jib --image test/test-api:0.0.0-dev                                                   1 err | 13:45:22 

> Task :jib FAILED
No classes files were found - did you compile your project?

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':jib'.
> com.google.cloud.tools.jib.plugins.common.MainClassInferenceException: Main class was not found, perhaps you should add a `mainClass` configuration to jib
  • MainClassInferenceException 에서 해결하는 데에 시간이 많이 걸렸다.

#3 디렉토리 변경을 했지만 gradle파일 없음

$ ./gradlew jib

zsh: no such file or directory: ./gradlew
  • 실행파일에 있는 모듈에서 ./gradlew가 아닌 gradle 명령어로 실행
  • Gradle Wrapper를 사용 유무의 차이

후기

로직 개발과 병행하여 적용하다보니 발생하는 오류코드들이 많았지만 메모할 여력이 부족해 더 기술하지 못한 부분이 아쉽다.
이전 프로젝트에서 sh파일을 이용해서 쉽게 처리했었지만 그래도 2~3분정도 걸렸었는데 7~20초 정도(평균 10초)로 단축되어 도커를 적용해 본 사람들이라면 꼭 한 번쯤 적용해보는 것을 적극 추천한다.


전체 소스 코드

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.12'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'com.google.cloud.tools.jib' version '3.1.4'
}

repositories {
    mavenCentral()
}

ext {
    serverEnv = System.getProperty('server.env', 'dev')
    springBootVersion = '2.7.12'
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'com.google.cloud.tools.jib'

    group = 'com.example'

    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_11

    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    repositories {
        mavenCentral()
    }

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

subprojects {
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

        implementation 'org.hibernate.validator:hibernate-validator:6.2.0.Final'
        implementation 'org.springdoc:springdoc-openapi-ui:1.6.7' // swagger

        compileOnly 'org.projectlombok:lombok:1.18.24'
        annotationProcessor 'org.projectlombok:lombok:1.18.24'
        annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

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

project(':module-api') {
    jib {
        if (serverEnv == 'dev') {
            from {
                image = 'openjdk:17.0.2-slim'
                platforms {
                    platform {
                        architecture = "arm64"
                        os = "linux"
                    }
                }
            }
            to {
                image = 'test/test-api'
                tags = ['0.2.6-dev','latest']
            }
            container {
                mainClass = 'com.example.ApiApplication' // 메인 클래스를 명시적으로 지정 module-api에서 이동해야 인식이됨
                jvmFlags = [
                        '-Dspring.profiles.active=dev',
                        '-Dfile.encoding=UTF-8',
                ]
                ports = ['8080']
                allowInsecureRegistries = true // Jib이 보안이 적용되지 않은 Docker 레지스트리와의 통신을 허용함
            }
        }
    }

    dependencies {
        implementation project(path: ':module-auth', configuration: 'default')
    }
}

project(':module-auth') {
    dependencies {
        implementation project(path: ':module-core', configuration: 'default')
    }
}

project(':module-core') {
    dependencies {
        implementation 'mysql:mysql-connector-java:8.0.29'
    }
}


bootJar {
    enabled = false
}
jar {
    enabled = true
}
profile
츠케멘 좋아
post-custom-banner

2개의 댓글

MainClassInferenceException 이거 어떻게 해결하셨나요..? ㅜ_ㅜ

1개의 답글