IT/Cloud

[Docker-Compose]Docker-Compose env parsing error로 인한 삽질기록

JeongHyeongKim 2021. 6. 24. 18:01

0. Table Of Contents

 

 

1. 문제 현황 분석

 

1.1. 문제 상황

docker version을 업그레이드 하고 나서 다음과 같이 잘 되던 .env file parsing이 잘 되지 않는 오류가 발생하였다.

 

 

1.2. 기존 docker version과 upgrade한 docker version

Mac Docker Desktop 기준으로 작성되었습니다.
  • 기존 Docker version : 3.0.0
    • Docker compose version : 1.27.4
    • Docker version : ?
  • 업그레이드 된 Docker version : 3.4.0
    • Docker compose version : 1.29.0
    • Docker version : 20.10.7

 

1.3. 프로젝트 폴더 구조

 

1.4. 명령어 call 순서

  • docker.sh를 이용하여 docker-start-local.sh 실행
  • docker-start-local.sh./docker-compose/docker-compose.postgres.yml를 참조하여 아래와 같은 명령어를 실행시킨다.
  • 업그레이드 전 아래 명령어는 정상적으로 동작하여 .env파일을 정상적으로 파싱하고 있었다.
docker-compose \
  -p {PROJECT_NAME} \
  -f ./docker-compose/docker-compose.postgres.yml \
  -f ./docker-compose/api/docker-compose.base.yml \
  -f ./docker-compose/api/docker-compose.local.yml \
  up $build --remove-orphans

 

 

1.5. 주요 파일 구성 확인

혹시나 싶어서 docker-compose.postgres.yml 파일과 .env가 제대로 구성이 안되어있는지 확인을 해본 결과 다음과 같았다.

version: '3'

services:
  postgres:
    image: <PROJECT_NAME>/postgres
    container_name: "<PROJECT_NAME>-postgres"
    build:
      context: ../docker/postgres
      dockerfile: Dockerfile
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - ../data/postgres/data:/var/lib/postgresql/data
      - ../docker/postgres/init/:/docker-entrypoint-initdb.d/
    ports:
      - "${POSTGRES_PORT}:${POSTGRES_PORT}"
    restart: unless-stopped
    ulimits:
      nproc: 65535
      nofile:
        soft: 65535
        hard: 65535
    healthcheck:
      test: ["CMD", "docker-healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"

 

# .env
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres

 

위와 같이 .envdocker-comspose.postgres.yml의 환경변수가 잘 매핑이 되어 있었기 때문에 parsing error가 날리가 없다고 생각했다.

 

 

 

 

2. 문제 해결 삽질

 

2.1. 문제 해결을 위한 searching

지금까지 어깨 너머로 배워서 docker-dompose를 사용하였지만, 문서를 상세히 보고 사용한 적이 없기 때문에 공식 document를 보면서 제일 먼저 정리하기로 했다.

Docker-Compose Command로 env를 정의하고, 실행했기 때문에, env file configuration 쪽을 찾아보는 도중 다음과 같은 문구를 발견 할 수 있었다.

 

출처 : Docker-compose Document

 

위 문서 중 내가 겪은 문제와 관련된 부분을 한글화하여 요약하면 다음과 같다.

1.28 미만의 Docker Compose의 경우, command가 실행된 현재 작업중인 directory에서 .env파일을 가지고 오거나, --project-directory argument에서 설장된 path에서 .env 파일을 가지고 옵니다.


이러한 모호함을 1.28 이상의 버전에서는 .env의 default path를 project directory로 제한하는 것으로 개선하였습니다. --env-file 옵션을 이용하여 기본 .env default path를 override 할 수 있습니다.


project directory는 다음 순서로 정의됩니다.

1. --project-directory flag에 정의된 path

2. 첫번째 --file (-f)로 flag에 정의된 directory

3. 현재 directory

 

 

2.2. 문제 디버깅

기존에 사용한 docker-compose version은 1.27.4였기 때문에 위 사항에 일치하였다. 위 사항을 이용하여 docker desktop 업데이트 이후 발생한 오류를 디버깅 해보면 다음과 같다.

  • 프로젝트 루트 폴더에서 shell script를 이용하여 docker-compose command를 실행시켰다.
  • 위에서 정의된 docker-compose command에는 project directory가 정의되어 있지 않다.
  • docker compose에 이용할 yml파일로 ./docker-compose/docker-compose.postgres.yml가 입력되었다.
  • project directory 정의 순서에 따라, ./docker-compose/가 project directory로 정의된다.
  • ./docker-compose/에는 .env 파일이 없다.
  • 없는 파일을 참조하였기 때문에 yaml파일 내부에서 ${}로 정의한 변수들이 전부 빈 string으로 대체된다.
  • postgresql port는 필수로 필요하지만, 입력이 되지 않았기 때문에 에러가 발생하였다.

 

 

2.3. 디버깅내용이 맞는지에 대한 검증

project directory인 ./docker-compose/에 루트 프로젝트 디렉토리에 있는 .env 파일을 다음 사진과 같이 복붙하여 .env파일을 하나 더 만든 다음 기존에 만들어 놓은 쉘스크립트를 이용하여 docker-compose를 실행시킨 결과, 정상적으로 docker가 빌드가 되어 정상적으로 실행까지 되었다.

 

2.4. 최종 문제 해결 flow

docker-compose 1.28.6 version release note를 보면 --env-file flag는 현재 작업중인 directory를 참조하도록 고쳐졌다고 한다.

 

 

env file을 제대로 인식 시켜주지 못하고 있기 때문에 이에 대해 명확히 설정을 해 줄 필요가 있다. compose에 사용되는 파일이 root project directory에 존재하기 때문에, docker-compose command 를 실행시킬 때, --env-file flag를 이용하여 명확하게 내가 사용하고자 하는 .env를 아래와 같이 명시해주었다.

 

 

 

3. 삽질을 통해 얻은 결론 및 개인적인 프로젝트 구조에 대한 회고

이처럼 실행환경에 대해서 정의할 때에는 최대한 사용할 파일들에 대해 command 또는 yaml, script에 정확히 명시를 하여 이러한 오류를 피해가게 하고, 다른 사람이 script를 읽었을 때 어떤 파일을 사용하는지 이해하기 쉽게 하는 것이 중요하다고 생각이 되었다. 향후, 위 문제처럼 다른 파일을 참조하고 있지만 묵시적인 방식으로 파일을 참조하고 있다면 명시적으로 나는 이걸 쓸거다라는 코드를 추가를 해야겠다.

 

+ env에 docker compose에서 쓰는 environment와 Dockerfile에서 사용하는 environment가 혼재하고있는데 향후 체계적으로 environment를 관리하기 위해서는 이를 분리하여 명확하게 어디서 쓰는 environment인지 정의하면 훨씬 더 좋을거같다.

 

 

 

4. Reference

Environment variables in Compose

Docker Compose release notes