이번 포스팅에서는 회사에서 가상환경을 띄우기 위해 Docker Compose 파일을 작성하면서 배우고 겪었던 Docker 관련 지식들을 정리하려고 한다.
회사에서는 이미 개발 서버용 Docker Compose 환경이 구축되어 있었다. 즉, 개발한 서버를 컨테이너로 띄워 로컬에서 테스트 및 개발할 수 있는 환경이었다. (테스트는 서버가 띄어져 있어야 가능한 테스트였다.)
하지만 어느 순간부터 이 Docker Compose 환경이 제대로 관리되지 않았고, 서버를 컨테이너로 띄워 테스트를 진행하는 것이 점점 어려워졌다. 결국 테스트를 하려면 로컬에서 서버를 싱행하고, 테스트 코드를 수동으로 수정하고 (주석 처리, 환경 세팅 등), 로컬에서 테스트 메인 함수를 실행해야만 integration test가 가능했다.
👉 즉, 서버는 뜨는데 테스트 환경은 따로라서 불편한 상황이었고, 이 과정은 우리 팀이 아닌 다른 팀원들에게는 매우 번거롭고 어려운 작업이었다.
그래서 나는 누구나 쉽게 테스트를 돌릴 수 있도록 Docker Compose 파일을 수정하고, integration test 역시 Docker 이미지로 실행되도록 환경을 구성하기로 했다. 사실 integration test 자체는 Docker Compose만 잘 구성하면 로컬에서 테스트 메인 함수를 실행해도 충분했지만, 팀 내에서는 CLI 명령어로 모든 걸 실행하는 개발자들도 있었기 때문에, “Docker Compose에 있는 서비스들을 모두 실행하면 integration test까지 자동으로 실행되도록 하면 더 편리하지 않을까?” 라는 생각이 들었다.
결국 integration test를 위한 가상환경 구축까지 진행하게 되었다.
겪은 문제점들과 해결법
1. DynamoDB 컨테이너 접근 문제
개발한 서버는 AWS 의 DynamoDB를 사용하고 있었는데, Docker Compose 로 서버 컨테이너와 DynamoDB 컨테이너를 띄우고 그와 별도로 만들었던 integration 테스트용 컨테이너를 띄워서 테스트를 실행했더니, 테스트 컨테이너에서 cannot do operation on non-existent table 에러가 발생했다.
분명 DynamoDB 컨테이너를 띄울 때 Table을 생성하도록 설정했는데도... integration 테스트를 로컬에서 그냥 돌리면(로컬 PC로) 저 에러가 안났다.
원인을 파악해보니 아래와 같았다.
원인: 네트워크 문제
- 테스트를 실행할 때 DynamoDB를 연결할 수 있는 주소를
http://localhost:8000이런 주소로 설정해 놓았고 DynamoDB 컨테이너가 해당 포트를 listen 하도록 설정했다. - 따라서, 로컬 PC에서 테스트를 실행하면
http://localhost:8000이런 주소로 DynamoDB 컨테이너를 잘 호출할 수 있는데, 테스트 컨테이너를 띄우고 실행하면, 그 컨테이너 안에서는localhost가 자기 자신을 가리켜서, DynamoDB 컨테이너를 못 보고 있는 상황이었다. 즉, DynamoDB 컨테이너는 local pc의 port 랑만 연결되어 있고, 테스트 컨테이너의 Port 와는 연결되어 있지 않은 것이다. - 위와 같은 상황을 통해 테스트 컨테이너가 테이블이 생성되어 있는 DynamoDB 컨테이너에 접근이 불가한 것이었다.
해결 방법
- 아래처럼 docker-compose.yml 에서 두 컨테이너를 같은 네트워크에 두고, 서비스 이름을 사용해서
http://dynamodb:8000으로 접근해야 한다.
services:
dynamodb:
image: amazon/dynamodb-local
ports:
- "8000:8000" # 이건 내 local pc 의 8000을 DDB 컨테이너의 8000으로 연결한다는 의미
api-test:
build: ./api-test
depends_on:
- dynamodb- 즉, 테스트 코드에서 DynamoDB 접근할 때 http://dynamodb:8000 으로 설정해야 정상적으로 실행 가능
2. 테스트 파일 생성/권한 문제
테스트 코드 내에서 테스트 실행 후 테스트 결과를 상대 경로(/app/summary-test.txt)로 파일을 생성하도록 되어 있었다. 그런데, 이를 테스트 컨테이너에서 실행하니까 테스트 실행 후 파일 생성 시 Permission denied 가 발생했다. (물론 로컬로 테스트를 돌리면 또 잘된다.)
원인
- 컨테이너 안에서 root 유저가 아닌 non-root 유저로 실행하고 있었는데, 이 유저는 host(내 로컬 PC)의 Volume 쓰기 권한이 없는 것이었다.
- working_dir 설정이 없으면 상대 경로 기준 혼동
해결 방법 (3가지)
- Dockerfile에서 권한을 열어주거나 (
RUN mkdir -p /app && chmod -R 777 /app) - docker-compose.yml에서 컨테이너 실행 시 유저를 권한 있는 유저로 바꿔주거나
- UID: User ID, 유저 번호 (id -u 로 확인 가능), GID: Group ID, 그룹 번호 (id -g 로 확인 가능)services: api-test: user: "0:0" # root(호스트 UID, GID) 로 실행 (문법 - user: "${UID}:${GID}")
- Dockerfile/Compose에서 WORKDIR (작업 디렉토리) 설정
- working_dir 이란? 컨테이너 안에서 프로세스가 실행될 때 기준이 되는 “현재 작업 디렉토리” (current working directory, CWD)로 컨테이너 안에서 “cd” 해놓고 시작할 디렉토리
- 우리가 로컬에서 터미널 열면 기본 경로가 ~ (홈 디렉토리)인데, 거기서 python main.py 같은 걸 실행하면, 상대경로(./summary-test.txt)는 그 위치 기준으로 해석된다.
- 컨테이너도 마찬가지로, 아무 설정 안 하면 기본 작업 디렉토리는 이미지마다 제각각 (/, /root, /usr/src/app 등)이다. 그래서 코드에서 ./summary-test.txt 를 쓰면 이상한 곳(심지어 read-only) 에 파일이 생기려다 Permission Denied가 날 수 있다.
- 아래처럼 working_dir 설정한다.
# docker compose 에서 하거나
services:
api-test:
build: ./api-test
working_dir: /app
volumes: # 컨테이너 내부 파일을 호스트와 동기화하는 통로
- ./api-test:/app # /app/summary-test.txt 가 ./api-test/summary-test.txt 로 파일 생김
# 아래처럼 DockerFile에서 설정
WORKDIR /app
COPY . . # 호스트의 . 를 /app/ 으로 복사
CMD \["python", "main.py"\] # python main.py 실행 시 /app 기준에서 실행됨추가 배운 것들
1. Docker 네트워크 개념
1) Docker Bridge Network 란?
- 브리지 네트워크(Bridge Network) 는 Docker가 제공하는 기본 네트워크 드라이버 중 하나로,
- 같은 브리지 네트워크에 연결된 컨테이너끼리 서로 이름으로 통신 가능: 같은 브리지 네트워크에 있으면, api-test 컨테이너에서
http://dynamodb:8000로 접근 가능 - Compose로 서비스 정의하면 모든 서비스가 자동으로 같은 커스텀 브리지 네트워크에 연결됨
2) 서로 다른 Docker Bridge Network를 사용한다면?
- 서로 다른 네트워크에 컨테이너가 있을 경우, 서비스명으로 통신 불가
- 컨테이너끼리 서로 직접 IP를 알거나 host port 에 바인딩 후 host 주소로 접근해야 연결 가능하다.
docker run -p 8000:8000 amazon/dynamodb-local # host port 에 바인딩docker run --network host api-test # host 모드 네트워크에서 api-test 실행, host 모드에서는 컨테이너 안에서도 localhost = 호스트 PC
3) 같은/다른 네트워크 설정 방법
- 같은 네트워크 -> compose 기본 설정이면 이미 같은 네트워크
- 다른 네트워크 -> 아래처럼 compose 작성 후 컨테이너 IP 직접 사용 (비권장) 하거나 host 포트 바인딩 후 host 주소 사용 (http://localhost:10080)
networks:
network-a:
network-b:
services:
dynamodb:
image: amazon/dynamodb-local
networks:
- network-a
ports:
- "8000:8000"
api-test:
build: ./api-test
networks:
- network-bDocker Compose 환경을 활용하면 개발 서버와 integration test를 동일한 네트워크에서 안정적으로 실행 가능하다.
이 작업을 통해 컨테이너 간 통신, 파일 권한, 포트 바인딩, DynamoDB 접근 문제 등은 대부분 네트워크 구조와 권한 설정에 대한 이해가 부족해서 발생했다.
이번 작업을 통해 Docker Compose를 활용한 실무 가상환경 구성 경험과 함께, 컨테이너 간 통신, 권한, 테스트 환경 구축에 대한 이해를 많이 높일 수 있었다.
'Life Style > 아무기록' 카테고리의 다른 글
| [나의 무지] 🤯 Spring RequestBody와 Static Inner Class: 오해와 진실 (1) | 2025.08.23 |
|---|---|
| [회사에서 있었던 일] 함수형 스타일로 개발하라? (0) | 2025.08.20 |