실습 1) Gradle을 활용한 빌드 준비

Hyerin·2022년 9월 17일
2

Gradle 이란?

Gradle은 Groovy를 이용한 빌드 자동화 시스템이다. Groovy와 유사한 도메인
언어를 채용하였으며, 현재 안드로이드 앱을 만드는데 필요한 안드로이드 스튜디오의 공식 빌드 시스템이기도 하다. Java, C/C++, 파이썬 등과 같은 여러 가지 언어를 지원한다.

거의 모든 소프트웨어를 빌드할 수 있도록 설계된 오픈 소스 빌드 도구이다.

Gradle 빌드의 세 가지 단계
1. 초기화단계 : Gradle에 빌드할 프로젝트를 설정하고 생성한다.
2. 구성단계 : 프로젝트 객체를 구성한다. 빌드에 포함할 프로젝트 빌드 스크립트나 테스크를 작성한다.
3. 실행단계 : Gradle의 모든 테스크를 빌드하고 실행한다.



Gradle 프로젝트의 구조

  1. gradle-wrapper
    gradlew 관련 repo 파일을 실행시키기 위한 파일

  2. gradlew
    리눅스, 맥OS용 쉘스크립트 파일

  3. gradlew.bat
    윈도우용 실행 batch 스크립트 파일

  4. settings.gradle
    프로젝트의 구성 정보 파일



Jib 이란?

Jib은 Docker 데몬 없이, 그리고 Docker 권장사항에 대한 깊은 숙달 없이
Java 애플리케이션에 최적화된 Docker 및 OCI 이미지를 빌드한다. Maven
Gradle용 플러그인과 자바 라이브러리로 사용할 수 있다.

  • 빠른 도커 이미지 빌드 및 배포가 가능하다.
  • 애플리케이션을 여러 layer로 분리하여 class 종속성을 분리해서 변경된 layer만 배포가 가능하다.
  • 도커 데몬이나 도커 CLI가 없어도 Gradle 안에서 도커 이미지를 빌드하고 원하는 이미지 repository로 push하는 명령어로 구성할 수 있다.

Jib과 기존 Dockerfile 기반 빌드 비교

Jib은 프로젝트를 빌드함과 동시에 컨테이너 이미지를 만들어서 원하는 도커 이미지 repository에 push한다.
Docker 빌드의 흐름이 하나의 흐름으로 합쳐진다.



Gradle Project 실습

실습환경

AWS EC2 Ubuntu 20.04
Gradle 7.1.1
Docker version 20.10.12
java


1) Gradle을 설치한다.


# 7.1.1 버전으로 다운로드한다.
$ wget https://services.gradle.org/distributions/gradle-7.1.1-bin.zip

# 압축을 푼다.
$ sudo unzip -d /opt/gradle gradle-7.1.1-bin.zip

# 링크를 연결한다.
$ sudo ln -s /opt/gradle/gradle-7.1.1 /opt/gradle/latest

# 환경변수를 설정한다.
$ sudo vi /etc/profile.d/gradle.sh

export GRADLE_HOME=/opt/gradle/latest
export PATH=${GRADLE_HOME}/bin:${PATH}

# 스크립트에 Executable 권한을 부여한다.
$ sudo chmod +x /etc/profile.d/gradle.sh

# 스트립트를 로딩한다.
$ source /etc/profile.d/gradle.sh

# Gradle 버전을 확인한다.
$ gradle -v 

Welcome to Gradle 7.1.1!

Here are the highlights of this release:
 - Faster incremental Java compilation
 - Easier source set configuration in the Kotlin DSL

For more details see https://docs.gradle.org/7.1.1/release-notes.html


------------------------------------------------------------
Gradle 7.1.1
------------------------------------------------------------

Build time:   2021-07-02 12:16:43 UTC
Revision:     774525a055494e0ece39f522ac7ad17498ce032c

Kotlin:       1.4.31
Groovy:       3.0.7
Ant:          Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM:          1.8.0_342 (Private Build 25.342-b07)
OS:           Linux 5.13.0-1029-aws amd64


2) gradle 초기화한다.

$ gradle init --dsl=groovy --type=java-application --test-framework=junit --package=com.test --project-name=test-docker-spring-boot

Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 7s
2 actionable tasks: 2 executed

3) 트리구조를 확인한다.

$ tree
.
├── app
│   ├── build.gradle
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── com
│       │   │       └── test
│       │   │           └── App.java
│       │   └── resources
│       └── test
│           ├── java
│           │   └── com
│           │       └── test
│           │           └── AppTest.java
│           └── resources
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

14 directories, 8 files


4) 더 자세한 빌드과정을 본다.

$ gradle build --info

Initialized native services in: /home/ubuntu/.gradle/native
The client will now receive all logging from the daemon (pid: 4379). The daemon log file: /home/ubuntu/.gradle/daemon/5.0/daemon-4379.out.log
Starting 2nd build in daemon [uptime: 52 mins 56.19 secs, performance: 97%]
Using 1 worker leases.
Starting Build
Compiling settings file '/home/ubuntu/settings.gradle' using SubsetScriptTransformer.
Compiling settings file '/home/ubuntu/settings.gradle' using BuildScriptTransformer.
Settings evaluated using settings file '/home/ubuntu/settings.gradle'.
Projects loaded. Root project using build file '/home/ubuntu/build.gradle'.
Included projects: [root project 'test-docker-spring-boot']

> Configure project :
Evaluating root project 'test-docker-spring-boot' using build file '/home/ubuntu/build.gradle'.
Compiling build file '/home/ubuntu/build.gradle' using SubsetScriptTransformer.
Compiling build file '/home/ubuntu/build.gradle' using BuildScriptTransformer.
All projects evaluated.
Selected primary task 'build' from project :
Tasks to be executed: [task ':compileJava', task ':processResources', task ':classes', task ':jar', task ':startScripts', task ':distTar', task ':distZip', task ':assemble', task ':compileTestJava', task ':processTestResources', task ':testClasses', task ':test', task ':check', task ':build']
:compileJava (Thread[Daemon worker Thread 2,5,main]) started.

5) docker 이미지를 생성한다.

$ vi build.gradle 

plugins {
  id 'java'
  id 'org.springframework.boot' version '2.6.2'
  id 'io.spring.dependency-management' version '1.0.11.RELEASE'
  id 'com.google.cloud.tools.jib' version '3.3.0' # jib 버전 3.3.0
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        developmentOnly 'org.springframework.boot:spring-boot-devtools'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

repositories {
  mavenCentral()
}

version = '0.0.1-SNAPSHOT'
description = 'test-docker-spring-boot'
group = 'com.test'

java.sourceCompatibility = JavaVersion.VERSION_11

jar {
        enabled = false
}

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

test {
        useJUnitPlatform()
}

jib {
  from {
    image = 'adoptopenjdk/openjdk11:alpine-jre'
  }
  to {
    image = 'hrleh/test-docker-spring-boot' # 도커허브에 미리 만들어둔 레파지토리
    tags = ['1.0']
    auth {
      username = 'hrleh' # 도커허브의 아이디
      password = '<password>' # 도커허브의 비밀번호
    }
  }
        container {
    entrypoint = ['java', '-Dspring.profiles.active=test', '-jar', 'test-docker-spring-boot-0.0.1-SNAPSHOT.jar']
    // mainClass = 'com.test.StartApplication'
    jvmFlags = ['-Xms512m', '-Xmx512m', '-Xdebug', '-XshowSettings:vm', '-XX:+UnlockExperimentalVMOptions', '-XX:+UseContainerSupport']
                ports = ['8080']

    environment = [SPRING_OUTPUT_ANSI_ENABLED: "ALWAYS"]
    labels = [version:project.version, name:project.name, group:project.group]

    creationTime = 'USE_CURRENT_TIMESTAMP'
    format = 'Docker'
        }
  extraDirectories {
    paths {
      path {
        from = file('app/build/libs') # app.jar 파일이 있는 경로
      }
    }
  }
}
$ ./gredlew jib

> Task :jib
No classes files were found - did you compile your project?
mainClass, extraClasspath, jvmFlags, and expandClasspathDependencies are ignored when entrypoint is specified

Containerizing application to hrleh/test-docker-spring-boot, hrleh/test-docker-spring-boot:1.0...
Base image 'adoptopenjdk/openjdk11:alpine-jre' does not use a specific image digest - build may not be reproducible
Using credentials from to.auth for hrleh/test-docker-spring-boot
The base image requires auth. Trying again for adoptopenjdk/openjdk11:alpine-jre...
Using base image with digest: sha256:44e3d55c056e1600af3b7f427ccfc93a5752ae3461a94295b954bc1a31d9fbcc

Container entrypoint set to [java, -Dspring.profiles.active=test, -jar, test-docker-spring-boot-0.0.1-SNAPSHOT.jar]

Built and pushed image as hrleh/test-docker-spring-boot, hrleh/test-docker-spring-boot:1.0
Executing tasks:
[==============================] 100.0% complete


BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed

도커허브에 push 성공


6) 이미지를 내려받아(pull) 컨테이너의 java 애플리케이션을 실행시킨다.

$ sudo docker pull hrleh/test-docker-spring-boot:1.0

1.0: Pulling from hrleh/test-docker-spring-boot
c7ed990a2339: Pull complete
4f6e4deaa459: Pull complete
fe739c7f04c7: Pull complete
2174954dbbb2: Pull complete
eff9b1d07d1e: Pull complete
07fc696c9a51: Pull complete
Digest: sha256:a3fa6bdf4a4d96a6d81f6da158535426d5fd7b417e462879abcaa0a09fcc1011
Status: Downloaded newer image for hrleh/test-docker-spring-boot:1.0
docker.io/hrleh/test-docker-spring-boot:1.0

$ sudo docker images
REPOSITORY                      TAG       IMAGE ID       CREATED         SIZE
hrleh/test-docker-spring-boot   1.0       c20e5812c2a2   7 minutes ago   168MB

$ sudo docker run -d -p 8080:8080 c20e5812c2a2
a97dc03a42b1ec73b2f981634fd476c2ba33dcb56ff3aeab7051610e4c5b2ac4

$ sudo docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS                          PORTS     NAMES
a97dc03a42b1   c20e5812c2a2   "java -Dspring.profi…"   About a minute ago   Exited (1) About a minute ago            charming_engelbart


오류모음

1. Docker 실행 오류

docker를 설치한 후에 실행하려고 했는데 에러메시지가 떴다.
특권을 갖지(privileged) 못한 컨테이너라서 발생하는 문제라고 한다.

$ sudo systemctl start docker
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

📍해결방법
관리자모드에서 docker 명령어를 실행시키면 된다.


2. gradle init 오류

$ gradle init --dsl=groovy --type=java-application --test-framework=junit --package=com.test --project-name=test-docker-spring-boot

FAILURE: Build failed with an exception.

* What went wrong:
Problem configuring task :init from command line.
> Unknown command-line option '--dsl'.

* Try:
Run gradle help --task :init to get task usage details. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 0s
$ ./gradlew jib
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

FAILURE: Build failed with an exception.

* Where:
Build file '/home/ubuntu/app/build.gradle' line: 3

* What went wrong:
An exception occurred applying plugin request [id: 'org.springframework.boot', version: '2.6.2']
> Failed to apply plugin [id 'org.springframework.boot']
   > Spring Boot plugin requires Gradle 6.8.x, 6.9.x, or 7.x. The current version is Gradle 4.4.1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 3s

📍해결방법
Gradle을 7.1.1 버전으로 다시 설치한다.



<출처>
Gradle설치 - https://codechacha.com/ko/installing-gradle/

profile
DevOps, 코딩 기록

0개의 댓글