https://start.spring.io/
위의 사이트에 접속하여, gradle에 Spring Web을 추가해준 후 프로젝트를 만든다.
기본 세팅으로 두고 프로젝트를 만들었다.
(Gradle-Groovy, Java, Jar, Java-17 | Dependencies - Spring Web)
프로젝트를 다운받으면, 압축을 해제하고 IntelliJ에서 열어준다.
배포 후 테스트를 위해서 간단한 Endpoint를 생성해준다.
따로 복잡하게 구성하지는 않고, Controller를 생성하여 코드를 작성해주었다.
@RestController
@RequestMapping("/api")
public class Controller {
@GetMapping("/connection")
public ResponseEntity<Object> getConnection() {
String result = "Success";
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
배포가 성공했다면, /api/connection
으로 접속했을 때 Success라는 글자가 보여야 한다.
이제 배포를 위한 Dockerfile을 생성해보자.
Dockerfile은 프로젝트의 루트 경로에 생성해야 한다.
그리고 Dockerfile의 내용을 채워보자 !
FROM bellsoft/liberica-openjdk-alpine:17
CMD ["./gradlew", "clean", "build"]
VOLUME /tmp
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
각 코드의 의미는 아래와 같다.
코드 | 내용 |
---|---|
FROM bellsoft/liberica-openjdk-alpine:17 | Java 17버전이 포함된 Docker 이미지 |
CMD ["./gradlew", "clean", "build"] | Gradle로 빌드 실행 |
VOLUME /tmp | 컨테이너 내에 /tmp 디렉터리를 볼륨으로 설정 |
ARG JAR_FILE=build/libs/*.jar | 빌드된 JAR 파일 경로를 변수로 설정 |
COPY ${JAR_FILE} app.jar | 빌드된 JAR 파일을 컨테이너 내의 app.jar로 복사 |
EXPOSE 8080 | 컨테이너에서 8080번 포트를 노출 |
ENTRYPOINT ["java","-jar","/app.jar"] | 컨테이너가 시작되면 java -jar /app.jar 명령을 실행하여 애플리케이션을 시작 |
VOLUME 부분이 이해가 잘 되지 않아서 추가로 검색해봤다 ..!
볼륨(Volume) 은,
데이터를 영구적으로 보관하기 위해 사용
일반적으로 컨테이너 내부 파일 시스템이 비휘발성이므로,
컨테이너가 삭제되거나 재시작할 경우 내부 저장 데이터가 사라짐.
이 때, VOLUME을 사용하면 지정된 디렉토리를 외부 스토리지로 연결해 컨테이너 종료 후에도 데이터가 유지됨
/tmp 디렉토리
/tmp는 리눅스 환경에서 임시 파일을 저장하는 디렉토리
자바 어플리케이션이나 웹 서버의 경우, 실행 중에 임시 파일이나 캐시 데이터를 /tmp에 저장할 수 있음
임시 데이터를 저장하는 /tmp 디렉토리에 볼륨을 설정하면, 컨데이너가 재시작되더라도 해당 데이터를 유지할 수 있음
특히, 컨데이너를 여러 번 재시작하거나 업데이트하는 경우 중요한 임시 데이터(세션 데이터, 캐시 등)를 잃지 않도록 해줌
호스트와의 데이터 공유
Docker가 이 디렉토리를 호스트 시스템의 디렉토리에 자동으로 연결해줌
이 경우, 호스트 시스템의 지정된 경로에 있는 데이터와 /tmp 디렉토리의 데이터가 동기화됨
또한, 다른 컨테이너가 동일한 볼륨을 사용할 수 있어 컨테이너 간 데이터 공유에도 사용 가능
데이터 보존의 이점
만일 컨테이너를 삭제하더라도 /tmp 디렉토리에 저장된 파일은 외부 볼륨에 남아있으므로 재시작 시 이 데이터를 그대로 사용 가능
=> VOLUME /tmp /tmp 디렉토리에 저장된 임시 데이터가 컨테이너가 종료되거나 삭제되더라도 유지되도록 외부 스토리지와 연결하는 설정
먼저, 이미지를 생성한다.
터미널에 아래의 명령어를 입력한다.
$ docker build -t [컨테이너 이미지 이름] .
[컨테이너 이미지 이름] 부분에는 본인이 생성할 이미지의 이름을 넣으면 된다.
위의 명령어를 실행하면 Docker에 이미지가 뜬 것을 확인할 수 있다.
그리고 컨테이너를 생성하고 실행하는 명령어를 입력한다.
$ docker run -d --name [컨테이너 이름] -p 8080:8080 [실행할 컨테이너 이미지 이름]
원하는 [컨테이너 이름] 으로 [실행할 컨테이너 이미지 이름]을 실행하는데, 호스트 기기의 8080 포트와 컨테이너의 8080 포트를 연결한다.
그런데 ...
뭔가 수월하다 했다 ... 오류가 난다 ! ㅎ.ㅎ
=> ERROR [2/2] COPY build/libs/*.jar app.jar
------
> [2/2] COPY build/libs/*.jar app.jar:
------
Dockerfile:9
--------------------
7 | ARG JAR_FILE=build/libs/*.jar
8 |
9 | >>> COPY ${JAR_FILE} app.jar
10 |
11 | EXPOSE 8080
--------------------
ERROR: failed to solve: lstat /var/lib/docker/tmp/buildkit-mount336840728/build/libs: no such file or directory
해당 파일이나 디렉토리를 찾을 수 없다는 내용인데, jar 파일이 없는건가 ..?
일단 생성한 컨테이너와 이미지를 차례로 삭제하고 다시 실행해봤더니,
Error: Unable to access jarfile /app.jar
이번엔 다른 오류가 난다 .. jar 파일에 접근할 수가 없다고 ?
이럴 때는 내가 설정한 경로로 들어가서 jar 파일을 찾아보면 된다고 하던데,
아니... 왜 build/libs에 jar 파일이 없나요 ..
보니까 libs 폴더도 만들어져 있지 않았다는 사실 ..! 정말 ㅜㅜ
이럴 때는 Gradle > Tasks > build > bootJar
를 실행해주면 된다 !
이미지에 보이는 bootJar를 실행해주면,
build/libs에 jar 파일이 생성된 것을 확인할 수 있다.
그 후 명령어를 다시 실행했더니, 문제 없이 잘 실행되었다 !
설정해둔 Endpoint도 원하는 대로 잘 나오는 것을 확인할 수 있었다
참고