1. Dockerfile 작성
# OpenJDK 8 사용
FROM openjdk:8
# 애플리케이션 디렉토리 생성 및 작업 디렉토리 설정
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# 현재 프로젝트의 파일을 컨테이너로 복사
ADD . /usr/src/app
# JAR 파일을 빌드하기 위한 Gradle 설정
RUN chmod +x ./gradlew
RUN ./gradlew :api:buildNeeded -x test
# 애플리케이션 실행 포트 설정
EXPOSE 8080
# 로컬 환경(Spring Profile: local)에서 실행되도록 설정
ENTRYPOINT ["java", "-Dspring.profiles.active=local", "-Duser.timezone=GMT+09:00", "-Djava.security.egd=file:/dev/./urandom", "-Djava.awt.headless=true", "-Dsun.net.inetaddr.ttl=0", "-Xms1024m", "-Xmx1024m", "-XX:MaxMetaspaceSize=128m", "-jar", "./api/build/libs/{jar_file_name}.jar"]
2. 애플리케이션 JAR 파일 빌드
Maven 프로젝트) 프로젝트 디렉토리에서 아래 명령어 입력
./mvnw clean package
Gradle 프로젝트) Gradle - Tasks - build - jar 버튼을 클릭해 생성


3. Docker 이미지 빌드
로컬에 설치된 Docker Desktop을 실행한 뒤 아래 명령어를 실행한다.
# 실행 권한 부여
sudo chmod +x gradlew
# docker build -t {image_name}:{tag} .
docker build -t core-api:latest .
$ docker images 명령어를 실행하면 아래와 같이 image가 생성된 것을 확인할 수 있다.

+ 에러 해결하기
ERROR: failed to solve: process "/bin/sh -c ./gradlew :api:buildNeeded -x test" did not complete successfully: exit code: 1 에러가 발생했다.
그 원인을 찾아보니 터미널의 java 컴파일 환경이 프로젝트의 버전과 일치하지 않아 발생한 문제 같았다. 프로젝트는 1.8 버전이지만 터미널에서 java -v 를 입력했을 때 17버전이 나왔다. Intelij로 실행했을 때는 정상적으로 작동해서 당연히 터미널로 해당 프로젝트에 이동했을 때도 정상 작동할 줄 알았는데, 각각 따로 동작한다고 한다.
Docker 환경에서 문제를 해결하기 전에, 로컬(터미널)에서 동일한 빌드 명령을 실행해서 오류가 재현되는지 먼저 확인했는데, 위에서 Docker build를 했을 때와 동일한 에러가 발생했다.
$ ./gradlew :api:buildNeeded -x test
문제 해결 순서
1. 프로젝트의 Gradle 버전 확인하기
기존에 있던 "gradle-wrapper.properties" 파일을 찾아 gradle-4.6-bin.zip 을 보고 프로젝트 버전을 확인했다.
2. 현재 JDK 버전 확인
아래 명령어를 통해 터미널에서 설정된 java 버전을 확인했는데, JDK 17버전이였다.
$ java -v
3. 프로젝트의 JDK 버전 설정
Gradle 4.6은 JDK 8에서 동작하기 때문에 기존에 컴퓨터에 설치된 내용을 확인해서 해당 프로젝트에서는 8버전을 사용하도록 설정한다.
# 설치된 모든 Java 버전 확인
$ /usr/libexec/java_home -V
# Java 8로 설정 (해당 프로젝트 디렉토리에서만 Java 8을 사용하도록 임시 설정)
$ export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
$ export PATH=$JAVA_HOME/bin:$PATH
이렇게 설정을 하면 1.8로 변경된 것을 확인할 수 있다.
영구적으로 Java 8 설정을 하려면 ~/.zshrc 파일을 열어 위의 내용을 추가한 뒤 source ~/.zshrc를 다시 입력하면 된다.
4. 프로젝트에서 Gradle Wrapper 실행
$ cd /path/to/your/project
$ ./gradlew wrapper
여기까지 완료하면 project_path/gradle/wapper/gradle-wrapper.properties 파일이 새로 생성된다.
..... 그래도 여전히 에러가 발생한다.
* Exception is:
#10 13.93 :api:compileQuerydsl (Thread[Task worker for ':' Thread 2,5,main]) completed. Took 4.709 secs.
#10 13.93 org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':api:compileQuerydsl'.
따라서 QueryDSL 코드 생성 우회 방법을 사용하기로 한다.
QueryDSL 코드 생성 우회하기
4. QueryDSL 코드 로컬 생성
$ ./gradlew :api:compileQuerydsl
보통 build/generated 또는 build/classes/java 경로에 생성되지만, 나의 경우에는 build.gradle을 확인해보니 아래와 같은 설정이 되어있었다. 즉 project_경로/src/main/querydsl 위치에 생성된 것을 확인했다.
querydslSourcesDir = "src/main/querydsl"
5. Dockerfile 코드 수정
Docker 빌드시 QueryDSL 코드를 다시 생성하지 않도록, 로컬에서 생성한 코드를 Docker 이미지에 포함한다.
# QueryDSL 코드 생성 우회: 로컬에서 생성된 QueryDSL 코드를 복사
COPY api/src/main/querydsl /usr/src/app/build/generated
따라서 최종 Dockerfile 내용은 아래와 같다.
# OpenJDK 8 사용
FROM openjdk:8
# 애플리케이션 디렉토리 생성 및 작업 디렉토리 설정
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# 현재 프로젝트의 파일을 컨테이너로 복사
ADD . /usr/src/app
# QueryDSL 코드 생성 우회: 로컬에서 생성된 QueryDSL 코드를 복사
# COPY local_querydsl_path container_querydsl_path
COPY api/src/main/querydsl /usr/src/app/build/generated
# JAR 파일을 빌드하기 위한 Gradle 설정
RUN chmod +x ./gradlew
# QueryDSL 코드 생성 단계 제외하고 빌드 실행
RUN ./gradlew :api:buildNeeded -x compileQuerydsl -x test --stacktrace
# 애플리케이션 실행 포트 설정
EXPOSE 8080
# 로컬 환경(Spring Profile: local)에서 실행되도록 설정
ENTRYPOINT ["java", "-Dspring.profiles.active=local", "-Duser.timezone=GMT+09:00", "-Djava.security.egd=file:/dev/./urandom", "-Djava.awt.headless=true", "-Dsun.net.inetaddr.ttl=0", "-Xms1024m", "-Xmx1024m", "-XX:MaxMetaspaceSize=128m", "-jar", "./api/build/libs/{file_name}.jar"]
6. Docker 이미지 파일로 저장
$ docker save core-api:latest -o core-api.tar
5. tar 파일을 이용해 이미지 로드
$ docker load < core-api.tar
6. 컨테이너 실행
# docker run -p {호스트머신_로컬_컴퓨터_노출_포트}:{컨테이너_내부_애플리케이션_포트} {image_name}:{tag}
$ docker run -p 18080:18080 core-api:latest
현재 실행하려는 서버는 18080 포트로 내부 애플리케이션과 소통하기 때문에 18080:18080 포트로 지정해주었다. 그리고 성공적으로 RUN!

'Study > Server' 카테고리의 다른 글
MySQL 워크밴치 연결시 Public Key Retrieval is not allowed 에러 해결하기 (0) | 2024.09.25 |
---|---|
[Kubernetes] 도커 데스크톱에서 쿠버네티스 사용하기 (Mac OS) (0) | 2024.09.23 |
[Kubernetes] Mac M1 - kubectl 설치하기 (ft. 카카오 클라우드) (0) | 2024.09.10 |
[NginX] Mac 로컬에 설치하기 (0) | 2024.08.27 |
[Jenkins] (3) 빌드 후 애플리케이션 자동 실행 설정 시도하기 (권장❌) (0) | 2024.08.27 |