최근 나는 사이드 프로젝트를 진행하고 있다. 그리고 사이드 프로젝트의 목표는 내가 공부한 내용을 적용 및 개선하는 것을 가장 큰 목적을 두고 진행하고 있다.
- 개발 초기 비용을 줄이는 것을 목표로 하여, 개발 환경 및 컨벤션을 통일한다.
- 코드 작성에 있어, 테스트 코드를 작성하고, 예측 가능한 코드를 작성한다.
첫번째 목표와 관련하여, 나는 개발 환경을 컨테이너 환경으로 구축했다. 개발 환경과 프로덕션 환경을 동일하게 하고, 다른 서비스와의 통신의 모의적으로 하기 위해서 컨테이너 환경으로 개발 환경을 구축했다. 그리고 컨테이너와 로컬 코드 베이스를 Docker Volume 으로 묶어 개발 과정에서의 코드 변경사항을 실시간으로 반영하였다.
그리고 나는 오늘 Docker Volume 과 관련한 문제를 겪었다. 이전에는 겪어보지 못한, 그리고 초기 환경 세팅 작업에서는 전혀 경험하지 못한 일이었다.
상황: 코드 변경사항이 반영되지 않음
현재 진행 중인 사이드 프로젝트는 FastAPI 기반의 Docker 개발환경으로 진행되고 있다. 그리고 나는 초기 환경 세팅 및 이미 도메인 하나를 개발한 뒤, 다음 도메인을 개발하는 과정에서 현재 문제에 직면했다.
- 코드를 수정했지만, 코드 수정이 반영되지 않았다.
- main.py 는 수정을 할 경우 수정사항이 반영(감지)되었지만, 개발중인 도메인은 반영(감지)이 되지 않았다.
- 개발 중인 도메인 브랜치가 아닌 main 브랜치로 변경하여 테스트해본 결과, 다른 도메인 코드는 변경이 반영(감지)됨을 확인했다.
나는 굉장히 당황스러웠다. 이전까지는 동작하던 코드가 갑자기 안된다니, docker 와 관련된 설정을 내가 변경한게 있는가? 부터 확인을 해보았으나, 수정된 사항은 없었다.
심지어 main 브랜치로 이동하여, docker 파일을 확인해본 결과 아무런 수정 사항이 없었다.
조치: Volume 관련 다양한 설정 시도
나는 이 문제를 해결하기 위해서 AI와 함께 디버깅을 하기 시작했다. 나는 가장 먼저 Volume 설정을 수정해보았다.
- 시도 1.
실패.볼륨 마운트를 bind 타입으로 명시적으로 지정하였다.(그러나, 나중에 확인해보니기존 설정에서도 Volume 마운트 설정은 올바르게 되어 있었다.) - 시도 2.
실패.uvicorn의 리로드 기능 코드를 모든 설정 코드에 작성하였다.(Override가 된 곳, 혹은 잘못 캐시된 부분이 있지않을까.. 하는 생각에 시도 하였으나, 역시나 이것은 문제가 아니었다. 이미지도 계속하여 다시 빌드하고 있었기에, 캐시된 부분이 있을 수 없었고, Override는 의도한 곳을 제외하고는 존재하지 않았다.) - 시도 3.
실패.watchfiles를 직접 사용하여 파일 변경을 확인한다.(파일 변경을 감지하지 못하는 상황은 아니었기에, 이 또한 문제가 해결되지는 않았다.) - 시도 4. 성공. 쓰기 권한 확인(로컬의 코드 수정이 컨테이너와 동기화 되는지 확인하는 과정에서 로컬에서는 변경이 반영되지 않았으나, 컨테이너에서의 변경은 로컬에 반영되는 것을 확인했다.)
성공한 방법. 쓰기 권한 확인
나는 다양한 시도를 진행해보면서, 무엇이 문제일지 도저히 감을 잡지 못했다.
- 왜, 갑자기 특정 파일만 수정을 감지하지 못하는가?(수정이 반영되지 않는가?)
- Volume 마운트는 올바르게 된 것을 확인했는데, 왜 동기화가 되지 않는가?
이런 고민을 하다, 갑자기 문득 권한 문제가 떠올랐다. 과거 코드를 서버 작업 및 초기 세팅을 할 때, 권한문제로 파일 생성, 수정이 안됬던 문제가 떠올랐다.
- 그러나, 권한이 문제라면 다른 코드들도 수정할 수 없어야 한다.
- 그리고 기본 값으로 읽기 및 쓰기 권한이 부여된다.
- 그럼에도 불구하고, 나는 이미 해볼 수 있는 방법은 다해보고 있었기에, 일단 해보자라는 생각으로 시도해보았다.
참고한 공식 문서 링크
그리고 놀랍게도 다시 docker-compose up을 했을 때, 정상적으로 코드 수정이 반영 되었다. 이와 관련하여, 공식문서에서는 문제의 원인에 대한 내용은 찾아보지 못했다. 그래서 나는 Claude 와 함께 상황을 설명하고 문제의 원인을 파악해보기 시작했다.
한참을 검색해보고 찾아본 결과, Docker Desktop의 구현 세부사항을 확인해봐야 정확한 문제의 원인 파악이 될 것으로 종결했다.
- :rw 옵션(기본 값)을 명시적으로 지정하여 문제가 해결되었다는 것을 감안할 때, Docker Desktop의 VM과 호스트 OS 간의 파일 시스템 권한 매핑 구현에서 문제가 된 것으로 보인다.
- 이 과정에서 암시적인(기본값) :rw 설정이 완벽하게 되지 않은 것이 아닐까?
- 검색을 통해 나오는 일반적인 케이스(권한으로 인한 로그 생성 오류)는 나의 경우와는 달랐다.. 유저를 선언하여 사용해도 적용되지 않았다.
아쉽지만 속 시원한 문제의 원인을 파악하지는 못했다. 그러나 이번 경험을 통해 한가지 깨달은게 있다. "기본은 특정 기술에 국한되지 않는다."는 것이다. 개인적으로 이번 현재 결과에 도달할 때가지의 과정이 아쉽다.
- 특정 파일만 수정이 감지 및 수정 반영 됨 -> 반영 시스템에는 문제가 없다. 라는 생각보다는 모든 과정을 의심했다.
- 볼륨 설정을 확인할 때, 원시적인 동작(수정사항 동기화)가 되는지를 확인을 가장 늦게 했다.
그리고 무엇보다 속 시원한 문제의 원인을 파악하지 못한 것이 제일 아쉽다.
사용한 docker 코드 파일 내용
# 기본 이미지
FROM python:3.11-slim as base
# 작업 디렉토리 설정
WORKDIR /app
# vim 설치를 위한 패키지 업데이트 및 설치
RUN apt-get update && apt-get install -y vim
# 패키지 설치를 위한 requirements.txt 복사
COPY requirements.txt .
# 개발 환경
FROM base as development
RUN pip install -r requirements.txt
# 개발 환경에서는 소스 코드를 복사하지 않음 (볼륨 마운트 사용)
# 프로덕션 환경
FROM base as production
RUN pip install -r requirements.txt --no-cache-dir
COPY . .
CMD ["uvicorn", "app.main:app", "--reload", "--host", "0.0.0.0", "--port", "${API_PORT:-8000}"]
# 기본 설정
version: '3.8'
services:
api-1:
container_name: app-api
build:
context: .
dockerfile: Dockerfile
environment:
- API_PORT=${API_PORT:-8000}
- API_EXTERNAL_PORT=${API_EXTERNAL_PORT:-18000}
- MONGO_HOST=${MONGO_HOST:-mongodb-1}
- MONGO_PORT=${MONGO_PORT:-27017}
- MONGO_DB=${MONGO_DB:-bleasy}
- POSTGRES_HOST=${POSTGRES_HOST:-postgres-1}
- POSTGRES_PORT=${POSTGRES_PORT:-5432}
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
- POSTGRES_DB=${POSTGRES_DB:-bleasy}
- ADMIN_API_KEY=${ADMIN_API_KEY:-bleasy-admin-2025}
networks:
- bleasy-network
depends_on:
postgres-1:
condition: service_healthy
mongodb-1:
condition: service_started
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "${API_PORT:-8000}"]
volumes:
- ./logs:/app/logs
// 다른 컨테이너 설정
volumes:
// 다른 컨테이너 볼륨 설정
networks:
// 네트워크 설정
# 개발 환경 설정
version: '3.8'
services:
api-1:
build:
target: development
ports:
- "${API_EXTERNAL_PORT:-18000}:${API_PORT:-8000}"
volumes:
- ./:/app:rw
- /app/__pycache__
- /app/**/__pycache__
- /app/.pytest_cache
- /app/venv
command: [ "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "${API_PORT:-8000}", "--reload", "--reload-dir", "/app" ]
environment:
- PYTHONPATH=/app
- PYTHONDONTWRITEBYTECODE=1
- PYTHONUNBUFFERED=1
- WATCHFILES_FORCE_POLLING=true
// 다른 컨테이너 설정