Spring

환경변수가 있었는데요? 없었습니다

recent0 2024. 11. 9. 18:20

서론


환경변수를 관리하고 있는 서버가 모종의 이유로 더 이상 서버에 접근할 수 없고, 사용하고 있는 환경변수를 백업하지 않았다면 환경변수 값을 정확하게 알기 어렵습니다. 그래서 이번 포스팅에서는 이미 올라가 있는 서버에 대해, JVM Heap Dump를 활용하여 환경변수를 찾아오는 방법에 대해 공유해드리고자 합니다.

사용한 기술 및 소프트웨어

Java11, Spring Boot 2.6.11, Docker, Filezilla

 

JVM Heap Dump?


일단 JVM Heap Dump에 대해 간단하게 소개를 드리겠습니다. JVM Heap Dump는 JVM의 힙 메모리에 저장된 모든 객체들의 스냅샷을 저장한 파일입니다. 해당 파일들은 다음과 같은 정보를 가지고 있습니다.

  1. 힙에 저장된 객체 정보
  2. 객체 간의 참조 관계
  3. 클래스별 메모리 사용량

JVM Heap Dump의 용도

위와 같은 정보를 바탕으로 다음 메모리 문제 원인에 대해 파악하고 해결할 수 있습니다.

  • 메모리 누수 감지: 메모리 누수로 인해 메모리 사용량이 증가하는 경우, 어떤 객체가 GC에 의해 제거되고 있지 않는지 확인할 수 있습니다(힙에 저장된 객체 정보, 객체 간 Strong reference).
  • 성능 문제 진단: 객체 생성 비용이 비싸거나 객체 생성이 빈번해 메모리를 많이 사용하는 경우에도 사용할 수 있습니다.

 

환경 변수 찾기


본격적으로 환경변수를 찾기 위해서 어떤 시도를 했는지 공유드리겠습니다. 이번 글은 아래와 같은 전제를 가지고 작성됐습니다.

  • 이미 도커 컨테이너로 서버는 동작하고 있는 상태
  • 환경변수를 관리하는 서버는 외부적인 이유로 더 이상 접근할 수 없는 상태

이제 JVM Heap Dump를 사용해 어떻게 환경변수를 확인했는지 설명드리겠습니다.

1. Docker Container에서 JVM 덤프 뜨기

1.1 JVM Heap Dump 사용할 컨테이너 확인

  • JVM Heap Dump를 사용하기 위해 PID를 확인해야 하는데, 그전에 대상이 될 Container ID를 획득합니다.
docker ps -a

실행중인 Docker Container 확인

1.2 Docker Container PID 확인

  • 파악한 Container ID를 통해, JVM Heam dump를 사용할 도커 컨테이너에 접속해 인터렉티브 셸을 시작합니다.
  • 이후 실행중인 프로세스를 확인하기 위해 procps 패키지를 설치한 뒤, 실행 중인 프로세스 PID를 확인합니다.
docker exec -it {:containerId} /bin/bash
yum install -y procps
ps -aux

실행중인 PID 확인

1.3 Docker Container JVM Heap Dump 뜨기

  • 이전에 확인한 PID를 기반으로 JVM Heap Dump를 수행합니다.
jmap -dump:format=b,file=/tmp/{filename} {pid}
exit

JVM Heap Dump 수행

1.4 Docker Conatiner에서 파일 다운로드

  • {id}에 해당하는 컨테이너의 /tmp/{filename} 파일을 현재 호스트의 디렉터리로 복사합니다.
  • 그리고 파일에 대해 권한을 재설정해주었습니다.
docker cp {id}:/tmp/{filename} .
chmod 777 {filename}
  • 복사한 파일은 FTP 툴인 Filezilla를 통해서 로컬로 다운로드 받았습니다. 
  • 복사했던 파일은 이후에 필요가 없기 때문에, 아래 명령어를 실행해 삭제해줍니다.
rm {filename}
docker exec -it {id} sh
rm /tmp/{filename}

 

2. JVM Heap Dump 결과물에서 환경변수 찾기

환경변수를 찾기 위해서 텍스트 툴을 사용할 수 있지만, Intellij 툴에서도 JVM Heap Dump 결과물인 hprof 확장자 파일 분석을 지원하고 있습니다. 그래서 이번에는 Intellij 툴을 활용해 주입받은 환경변수를 찾아보고자 합니다. 주입받은 환경변수 값들은 한 곳에 저장되어 있는 게 아니기 때문에, 원하는 변수를 찾기 위해서는 패키지 경로 및 클래스명 정보가 필요합니다.

2.1 환경변수 찾기 예시 코드

  • 예를 들어 사용하고 있던 JWT Secret Key를 잃어버렸다고 가정해 보겠습니다. 아래는 환경변수가 주입된 클래스 예시입니다.
@Service
@RequiredArgsConstructor
public class JwtService {

    @Value("${jwt.secretKey}")
    private String secretKey;

    @Value("${jwt.access.expiration}")
    private Long accessTokenExpirationPeriod;
    
    //... JWT 관련 로직
}

 

2.2 환경변수 확인하기

Intellij에서 다음 순서를 통해 환경변수를 확인할 수 있습니다.

  1. 다운로드한 hprof 파일을 intellij에서 실행시킨다.
  2. 찾으려는 클래스명을 검색하여 패키지 경로까지 확인하여 일치한 지 확인한다.
  3. 대상 클래스를 더블 클릭하고 찾으려는 환경변수에 대해 확인한다.

그러면 아래와 같이 입력했던 환경변수 값을 확인할 수 있습니다.

주입했던 환경변수 값 확인

느낀 점

단순히 JVM Heap Dump를 사용하는 경우는 어플리케이션 서버에 메모리 이슈가 있을 때만 있을 거라고 생각했는데, 환경변수도 확인 가능하다는 것을 추가로 습득할 수 있었습니다. 이번 환경변수를 찾는 과정에서 JVM Heap Dump에 조금 더 찾아봐야겠다는 생각이 들었습니다. 읽어주셔서 감사합니다.

'Spring' 카테고리의 다른 글

Gradle 설정 알아보기 (1편)  (0) 2025.02.16
Flyway 도입 전 탐색해보기  (2) 2024.12.07
JPA 양방향 매핑 탈출기  (0) 2024.10.27
@PathVariable 엔드포인트 매핑 원리  (1) 2024.10.12
Redis, 그리고 Spring 에서 Redis 활용  (6) 2024.09.07