CI/CD를 위해 코드 컴파일, 테스트, 패키징, 의존성 관리, 배포 등 빌드 과정을 자동화해준다.
빌드 도구로는 Gradle외에도 Ant, Maven가 있는데 이 중 Gradle은 캐싱을 이용하여 빠른 빌드가 가능하다.
Gradle을 사용하기 위해서는 시스템에 Gradle이 설치되어 있어야 하며, 사용자가 원하는 버전을 관리해야 한다.

Gradle은 Groovy문법을 기반으로 초기화->구성->실행 단계에 따라 작동한다.
초기화 단계는 setting.gradle과 루트 build.gradle을 이용하여 설정과 빌드할 프로젝트 단위를 결정한다.
구성 단계는 build.gradle단계에서 생성된 인스턴스들에게 빌드 설정을 적용시킨다.
실행 단계는 구성 단계에서 만든 프로젝트 task 중 실행할 대상을 결정한다.
위 작업은 사용자가 빌드하면(./gradlew build) 순차적으로 진행된다.
이 때 구성단계에서 Gradle은 소스코드와 설정의 변경 유무를 확인하고, 변경사항이 없다면 build task가 아닌 'UP-TO-DATE'라고 표시하며 작업을 건너뛴다.

빌드 자동화 시스템 자체를 의미하는 Gradle과 달리, Gradle Wrapper는 특정 버전의 Gradle을 프로젝트에 포함시켜 gradle의 사전설치 없이 일관된 빌드 환경을 제공하는 도구이다. 이를 통해 개발자는 별도로 Gradle을 설치하거나 관리할 필요가 없다. 다만 첫 실행 때 Gradle 버전을 다운로드 해야하기에 인터넷 연결이 필요하다.
이를 이용하여 여러 환경에서 개발하는 팀 프로젝트의 경우 특정 Gradle버전을 강제하여 일관된 빌드 환경을 제공할 수 있다. 특히 Gradle버전을 자주 변경해야 할 필요가 있는 경우나 상업적 개발 환경에 적절하다.
gradle wrapper는 gradle/wrapper/gradle-wrapper.jar을 이용해 gradle daemon 실행을 위한 프로세스를 올린다.
Gradle의 장점인 캐싱을 Gradle Daemon이 수행한다. Gradle Daemon은 빌드 간 정보를 유지하는 백그라운드 프로세스로, 빌드 시 필요한 데이터를 캐싱하여 후속 빌드에서 빌드 시간을 단축시킬 수 있다.
JVM 관점에서 Gradle사용 시 사용자 요청을 아래와 같이 처리한다.

유저가 Gradle Client JVM에 사용자 요청을 전달하면, Gradle Client JVM은 Gradle Daemon JVM에 요청을 보낸다. 그 후 Gradle Daemon JVM은 전달된 build script를 실행하여 결과를 Gradle Client JVM에 반환한다.
build 실행 이후 Gradle Client JVM은 종료되지만, Gradle Daemon JVM은 일정시간동안 유지되며 Gradle을 캐싱하여 빌드 할 수 있게 한다.
RecoPlatform-2.0 백엔드 서버를 빌드하는 과정에서 아래와 같은 Gradle 빌드 오류를 발견했습니다.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':kaptGenerateStubsKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
> Internal compiler error. See log for more details
이는 Kotlin 코드를 처리하는 kapt 작업 중 컴파일러 내부에서 문제가 발생한 것인데, 프로젝트에서 사용하는 Kotlin 버전과 JDK 버전 간의 호환성 문제입니다. 즉, 올바르지 않은 JDK가 설정된 것입니다.
이를 해결하기 위해 Java 버전을 명확히 관리해주는 jenv를 이용해 JDK를 Amazon Corretto 11 로 수정하였습니다.
jenv add /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
jenv local corretto64-11.0.28
위처럼 JDK 버전을 corretto 11로 올바르게 설정하였지만 빌드 오류가 계속되었습니다.
문제는 Gradle이 빌드를 수행하는 방식이었습니다.
Gradle을 이용하여 빌드를 수행하는 과정에서, 최초 빌드 시 Gradle Daemon JVM이 일정시간 남아있게 됩니다. 이 때 Gradle Daemon JVM은 빌드 시 빌드에 필요한 정보를 가지고 있어 캐싱데이터를 사용하게 됩니다. 그러므로 이후에 jenv를 이용해 jdk의 버전을 바꾸더라도 이 변화를 알아차리지 못하고 캐싱데이터를 사용하여 이전 버전의 jdk로 빌드를 수행하여 오류가 발생한 것이었습니다.
Gradle Daemon JVM은 데몬 프로세스가 시작될 때의 환경 변수 설정을 그대로 유지합니다.
근본적인 원인을 찾기위해 프로세스의 환경 변수가 상속되는 방식을 알아보았습니다.
이러한 Gradle Daemon의 동작 방식은 빌드의 일관성을 보장하는 데 도움을 주지만, 빌드 스크립트가 특정 환경 변수에 따라 다르게 동작하도록 설정한 경우와 같이 동적으로 환경변수를 변경하며 작업하는 경우 문제가 발생할 수 있습니다.
가장 간단한 해결책은 아래 명령어로 실행 중인 모든 Gradle Daemon을 중지하는 것입니다.
./gradlew --stop
혹은 데몬 생성없이 일회성으로 빌드를 실행시킬 수 있습니다.
./gradlew --no-daemon <stask>