[Spring Boot] Docker를 통해 Spring Boot 배포 시 로그 남기는 방법

임원재·2024년 11월 24일
0

SpringBoot

목록 보기
10/19
post-thumbnail
  • 처음 Spring Boot를 빌드하여 도커를 통해 EC2에 배포했을 때 다음의 명령어로 이미지를 실행하였다.
docker run --name={project_name} -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/{project_name}:latest
  • 해당 명령어는 컨테이너 이름을 {project_name}로 설정하고, 호스트가 8080포트로 접속하면 해당 컨테이너가 존재하는 8080포트로 전달되게 함을 의미한다.
  • 다음과 같이 도커 이미지를 run하면 Spring Boot가 실행되며 바로 로그가 출력된다.
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.4)

2024-11-24T17:08:44.616+09:00  INFO 15576 --- [persist] [           main] yyytir777.persist.PersistApplication     : Starting PersistApplication using Java 17.0.8.1 with PID 15576
2024-11-24T17:08:44.618+09:00  INFO 15576 --- [persist] [           main] yyytir777.persist.PersistApplication     : The following 1 profile is active: "prod"
2024-11-24T17:08:45.217+09:00  INFO 15576 --- [persist] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2024-11-24T17:08:45.286+09:00  INFO 15576 --- [persist] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 63 ms. Found 3 JPA repository interfaces.
2024-11-24T17:08:45.792+09:00  INFO 15576 --- [persist] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
...(생략)
  • 하지만 이의 단점은 로그 출력 화면이 터미널을 독점하게 된다. 해당 화면을 나가려면 ctrl + c를 통해 나가는 방법밖에 없다.
  • 더군다나 화면을 나가게 되면 해당 컨테이너는 종료상태가 된다 즉, 해당 컨테이너의 실행 상태를 유지하려면 로그 화면을 유지하는 방법밖에 없다.
  • 처음에는 백그라운드에서도 컨테이너가 실행상태를 유지하는 방법을 몰랐었다. 도커 이미지를 실행시킬 때 -d 옵션을 통해 백그라운드에서 컨테이너를 실행할 수 있다.
docker run --name={project_name} -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/{project_name}:latest
  • 이를 통해 로그 출력 화면을 보지 않고 컨테이너를 실행하는 동시에 터미널을 사용할 수 있게 된다
  • 하지만 이렇게 되면 로그는 어떻게 확인해야할까? 해당 애플리케이션에 오류가 발생했을 때 로그를 확인해야하는데 확인할 수 없게 되었다.
  • 구글링을 하며 백그라운드에서 컨테이너를 실행하면서 로그를 확인할 수 있는 다양한 방법을 찾아보았다.

첫 번째 방법

  • nohup이라는 명령어를 사용하는 방법이다. HUP신호를 무시하도록 만드는 POSIX명령어라고 한다.
  • 터미널로 향하는 출력을 넘겨주기 처리를 하지 않았을 경우 nohup.out이라는 이름의 파일로 처리된다.
  • 사용법은 실행하고자 하는 명령어 앞에 nohup을 붙여주기만 하면 된다.
  • Spring Boot의 jar파일을 실행하는 Dockerfile의 명령어에 붙여줄 수 있다.
FROM openjdk:17-jdk  
  
ARG JAR_FILE=build/libs/project_name-0.0.1-SNAPSHOT.jar  
  
COPY ${JAR_FILE} /project_name.jar  
  
ENTRYPOINT ["nohup", "java", "-jar", "-Dspring.profiles.active=prod", "/project_name.jar"]
  • 이렇게 하면 될 줄 알았다... 문제는 도커를 통해 jar파일을 실행하고 있다는 것이었다.
  • nohupshell에서 실행되는 명령어이다. Dockerfile에서의 ENTRYPOINT의 명령어는 엄밀히 말해 shell이 아닌 도커 컨테이너에서 실행되는 명령어였던 것이다.
  • nohup을 사용하려면 도커가 아닌 직접 jar파일을 실행하면 된다.
nohup java -jar project_name.jar
  • 이때는 도커를 사용하지 않으므로 java를 실행할 수 있도록 맞는 버전의 java jdk를 설치해야한다.
  • 도커와는 어울리지 않는 방법이므로 다른 방법을 또 찾아보았다.

두 번째 방법

  • 다음과 같은 방법을 찾아냈다.
FROM openjdk:17-jdk 
ARG JAR_FILE=build/libs/proejct_name-0.0.1-SNAPSHOT.jar 
COPY ${JAR_FILE} /proejct_name.jar 
ENTRYPOINT ["sh", "-c", "java -jar -Dspring.profiles.active=prod /proejct_name.jar > /logs/application.log 2>&1"]
  • > /logs/application.log는 출력을 /logs/application.log에 저장하겠다는 의미이며, 실행 중에 발생하는 메세지가 파일에 기록된다
  • 2>&1의 의미는 다음과 같다.
    - 2>는 에러의 리다이렉션,
    - &1는 출력의 파일 디스크립터의 참조
  • 즉, 에러와 출력을 같은 파일에 기록하라는 뜻이라고 한다.
  • sh - csh명령어로 뒤에 오는 문자열을 명령어로 실행하도록 지시한다.
  • "java -jar -Dspring.profiles.active=prod /proejct_name.jar > /logs/application.log 2>&1"라는 복합 명령어를 실행할 수 있도록 하는 명령으로 이해하였다.
  • 해당 Dockerfile로 도커 이미지를 실행하였더니 /logs/application.log파일에는 아무것도 기록되지 않았다.
  • 쓰기 권한이 없나 싶어 /logs폴더에 다음과 같이 권한을 수정하였지만 바뀌는건 없었다.
chmod -R 777 /logs

세 번째 방법

  • 너무나도 쉬운 방법이 있었는데 완전히 돌아갔다...
  • 도커 자체에서 컨테이너의 출력을 로그 시스템에 저장한다는 것이었다. docker Docs
  • 위의 링크에 따르면,
    docker logs --option [container id || container name]
    를 통해 해당 컨테이너의 STDOUT과 STDERR(표준출력, 표준에러)를 확인할 수 있다.
  • 사용 가능한 옵션은 아래와 같다.
OptionDefaultDescription
--details디테일한 추가 로그를 제공
-f, --follow실시간 로그를 보여줌
--since특정 시간 이후의 로그를 보여줌
-n, --tailall끝에서부터 n개의 로그를 보여줌
-t, --timestamps각 로그 앞에 타임스탬프를 보여줌 (Spring Boot에서는 필요 X)
--until특정 시간 이전의 로그를 보여줌
Example

docker logs --details <container>

docker logs -f <container>

docker logs --since="1h" <container>

docker logs --since="2024-11-24T11:12:00Z" <container>

docker logs -n 100 <container>

docker logs -t <conatiner>

docker logs --until="1h" <container>

  • 이렇게 사용자의 요구사항에 맞게 다양한 형식으로 도커 컨테이너의 로그를 출력할 수 있다.
  • 이것도 모르고 자꾸 엄한곳을 파고 있었다...
  • 이렇게 되면 설정 파일은 다음과 같게 된다.
Dockerfile

ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "/project_name.jar"]

  • nohup을 붙이지 않아도 된다.
gradle.yml

docker run --name=project_name -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/project_name:latest

  • 백그라운드에서 실행한다는 의미의 -d를 붙여야 한다.

  • 이제 docker logs <container>를 통해 쉽게 로그 확인이 가능해졌다.
  • 공식 문서만 조금 읽어도 해결 가능했는데 왜이렇게 돌아가려고 했는지 후회된다.
  • 앞으로 어떤 기술에 대해 알고자 할 때 공식 문서를 먼저 훑어보는 버릇을 들이고자 노력해야겠다.

0개의 댓글