[프로젝트/픽잇] Docker 적용 과정

슬링민키·2025년 8월 26일

픽잇

목록 보기
3/7
post-thumbnail

도입 배경

프로젝트를 시작하게 되면서 어떻게 프로젝트를 관리하고 실행할지에 대해서 고민하게 되었다.
프로젝트를 실행하고 관리하면서 우리가 중요하다고 생각한 것은 실행환경의 일관성이었다.

백엔드 개발자가 4명인데 이때 2명은 맥OS를 사용하고 2명은 Window를 사용하고 있었다.
팀원들의 운영체제가 서로 달라 생기는 문제까지 고려하기에는 불필요한 작업들이 생길 수 있을 것 같다.

또한 배포환경을 생각했을 때 로컬 환경에서의 예상과는 다르게 문제가 생길 수 있다고 생각하였다.

따라서 이와 같은 이유들의 해결책으로 Docker를 사용하기로 하였다.
Docker hub의 이미지를 활용하여 이미지 공유 및 배포에서도 유리한 이점을 가져갈 수 있다고 생각하였다.

설계 과정

Docker를 활용하는 방법은 프로젝트가 실행되면서 많이 변경되었다.

DockerFile을 통해서 빌드하여 직접 실행하던 방식을 이번에 기록하고 Docker 이미지를 더 잘 활용하게 된 과정은 은 프로젝트의 CI/CD 블로깅에서 다룰 예정이다.

[DockerFile을 통해 직접 실행하여 Docker를 사용]

# 빌드용 jdk AS 키워드를 사용하여 해당 스테이지 이름을 build로 설정
FROM eclipse-temurin:21 as build 

WORKDIR /app

# Gradle 관련 파일 복사
COPY build.gradle .
COPY settings.gradle .
COPY gradlew .
COPY gradle ./gradle

# 의존성 다운로드
RUN ./gradlew clean --no-daemon || true

# 소스 코드 복사
COPY src ./src

# 빌드 (테스트 제외)
RUN ./gradlew bootJar -x test --no-daemon

# 실행용 jre
FROM eclipse-temurin:21-jre

WORKDIR /app

# 빌드 결과물 복사
COPY --from=build /app/build/libs/*.jar app.jar

EXPOSE 8080

# 실행 (실시간 로그 확인 가능)
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS:-} -Dspring.profiles.active=${SPRING_PROFILES_ACTIVE:-default} -jar /app/app.jar"]

DockerFile멀티스테이징 기능( 하나의 DockerFile 안에서 빌드용 스테이지와 실행용 스테이지를 분리하는 방식)을 활용해서 Docker 이미지를 가볍게 사용할 수 있다.
마치 2개의 DockerFile을 사용하는 것과 같은 효과이다.

이를 활용해 build를 하는 과정에서는 JDK를 사용하고, 빌드된 결과물을 실행할 때는 JRE를 사용하였다. 즉, 빌드 과정에서만 무거운 개발 도구(JDK, Gradle 등)를 사용하고 최종 실행 환경에는 꼭 필요한 실행 파일(JRE와 빌드 산출물)만 담을 수 있다.

이 방식은 이미지 크기를 줄이고, 보안상 불필요한 도구나 소스코드가 최종 배포 환경에 포함되지 않도록 해준다.

이렇게 만든 DockerFile을 Docker-compose를 통해 빌드·실행하거나 직접 빌드하여 이미지로 만든 뒤 Docker Hub에 push해서 EC2에서 가져와 사용할 수 있다.

Docker를 활용하고 또 멀티스테이징이라는 키워드를 알고나서 헷갈리는 부분들이 많았다.
예를 들어 WORKDIR /app은 내 로컬 프로젝트의 /app을 가리키는 줄 알았는데, 실제로는 컨테이너 내부의 디렉토리라는 걸 알게 되었다.

또 스테이지마다 독립된 파일시스템이 존재하기 때문에 같은 /app이라도 build 스테이지의 /app과 runtime 스테이지의 /app은 서로 다른 공간이다.
따라서 앞 스테이지에서 만든 산출물을 최종 스테이지로 가져오려면 COPY --from=build /app/build/libs/*.jar app.jar 처럼 명시적으로 가져와야한다.

빌드 스테이지의 컨테이너는 임시로 작업 후 스냅샷(레이어)을 남기고 사라지며, 그 결과물만 최종 이미지에 포함되는 구조다.

이렇게 하여 최종이미지에는 불필요한 빌드과정을 사라지고 최종 build된 파일,JRE 와 run을 할 시점에 실행할 ENTRYPOINT를 통해서 빌드 결과물을 실행하게 된다.

정리하면, 멀티스테이징을 사용하면 불필요한 빌드 도구가 최종 이미지에 포함되지 않고, 실행에 필요한 산출물만 남기게 된다. 따라서 최종적으로 만들어진 이미지는 가볍고, 보안상 안전하며, 운영 환경에 최적화된다.

Docker를 도입했을 때 장점

실행환경의 일관성

  • Docker를 활용했을때의 장점으로는 앞선 도입 배경과 같이 통일성 있는 실행 환경이다. 운영체제와 같은 실행 환경이 다른 경우에 어플리케이션 실행에 문제가 생기는 것을 막을 수 있다.

운영환경 테스트

  • 미리 로컬에서 Docker를 실행해 운영환경과 똑같이 실행해볼 수 있다는 것도 장점이 될 수 있을 것 같다.

Docker 이미지 활용

  • Docker Hub를 사용하여 이미지를 올려둔 후에 이를 사용하게 된다면 프로젝트를 버전별로 관리하거나, 문제가 생겼을 때 특정 버전의 이미지를 가져와 손쉽게 롤백할 수 있어 편리하다.

격리된 애플리케이션 환경

  • Docker에서 여러 컨테이너를 생성,삭제하며 여러개의 격리된 애플리케이션을 실행할 수 있다. 격리된 환경은 애플리케이션의 오류를 찾을때 도움이 되고 서로 다른 애플리케이션에게 영향을 주지 않는다는 점이 좋은 것 같다.

Docker를 도입했을 때 단점 혹은 주의할 점

학습 곡선

  • 이번 프로젝트를 진행하면서 원래 Docker에 익숙하지 않았다. Docker를 사용하기 위해서 처음에 알아야할 것들이 꽤 많았다. 잘못된 설정을 하기 쉽고 이미지를 무겁게 만들 수도 있다. 실제로 이후에 CI/CD 에서 빌드를 2번하는 바람에 빌드시간이 엄청 오래 걸렸을 때도 원인을 바로 찾지 못했던 경험이 있다. 학습 곡선이라는 이유는 프로젝트에서 충분히 납득가능한 이유이다.

보안

  • 앞선 학습 곡선에 이어지는 문제인데 Docker를 사용하다 보안적인 부분을 놓칠 때도 많다. 처음에 .env파일을 사용하여 최대한 감춰야할 부분들을 최대한 가리며 사용하고 있었다.
  • 이때 docker-compose.local.xml에서는 DB만을 Docker를 사용하고 있는데 예전에 작성해둔 MYSQL_USER와 MYSQL_PASSWORD 가 남아있었다. 이때 사용하던 아이디와 비밀번호가 아직 그대로 github에 공개되어있었다. 이후에도 사용하고 있는 USER와 PASSWORD여서 문제가 될 수 있었다. 물론 현재의 production DB에 접속하려면 보안그룹 설정으로 막혀있지만 사소하게 놓치는 부분이 있었다는 점이 보안으로 위험할 수 있었던 것 같다.

설계 회고

우리 팀은 Docker를 빠르게 사용하기로 결정하고 사용하여 쭉 진행하였다. Docker만을 위해 따로 공부하지 않았었기에 사용하는 과정에서 어려웠던 순간들은 많았다. Docker 이미지를 배포하고 관리하는 과정에서 새로운 학습이 필요했다.

Docker 가 필수냐?

Docker가 필수냐? 라는 질문에는 나는 "그렇지 않다" 라고 답할 것이다.

사실 Docker를 꼭 사용하지 않더라도 해결 할 수 있는 방법은 존재했을 것이다. 단일 컨테이너 환경이라면 Docker 없이도 운영이 충분히 가능하다 .

Docker를 사용하게 되면서 관리해야하는 부분도 신경써야한다. 누군가에게는 Docker 사용이 익숙하지 않은 상황일 수 있다. Docker 이미지 크기의 비용도 분명 존재한다.

한번은 프로젝트에서 Docker 이미지가 쌓이면서 실제 서버 디스크가 빠르게 차올랐고, 빌드 캐시 관리가 중요한 이슈가 되었다. 이처럼 성능과 저장 공간에도 직접적인 영향을 준다.

Docker가 가진 장점이 더 크다고 생각

그러나 Docker의 장점이 내게 더 크게 느껴지는 것 같다. 장점중에 제일 크게 느끼는 것은 운영 환경과 개발 환경의 일관성이다. 이 하나의 이유만으로도 사용할 이유가 충분히 되었다.

Docker 이미지를 활용한 배포과정 및 롤백, 여러 애플리케이션의 독립된 환경 등 개발자로써 관리해야하는 부분을 줄여준다고 느낀다.

또 이번 과정을 통해서 Docker에 대해 충분히 학습 할 수 있었다. 부족한 부분들에 대해서는 점점 채워나가며 Docker를 사용하며 놓칠 수 있는 부분들을 점차 보완할것이다.

도입 이유는 역시 중요하다.

특정 라이브러리나 도구를 도입할 때는 우리 프로젝트에서 왜 필요한지 그 이유가 명확해야 한다. 도입 근거가 부족하다면 프로젝트를 불필요하게 무겁게 만들고, 과도한 설계로 이어질 수 있다.
앞으로도 새로운 도구를 추가할 때는 도입 목적을 분명히 하고, 장단점을 검토한 뒤 채택 여부를 결정할 것이다.

profile
하루하루는 성실하게 인생 전체는 되는대로

0개의 댓글