[IT-정보] docker compose yml 실수 유형과 해결법 – 운영 사고를 막는 핵심 설정 패턴

docker-compose.yml 기본 문법를 설명하는 흔한 실수 모음 대표 이미지

작은 설정 한 줄이 불러오는 거대한 운영 사고

새벽 2시, 조용하던 사무실에 갑자기 서버 장애 알람이 울려 퍼져요. 급히 로그를 확인하니 모든 컨테이너가 무한 재시작 상태에 빠져 있어요. 당황스러운 마음에 어제 수정했던 docker-compose.yml 파일을 열어보니, 정말 말도 안 되는 곳에서 실수가 발견돼요. 단 한 칸의 들여쓰기가 잘못되었거나, 환경 변수 하나에 따옴표가 빠진 것뿐인데 전체 서비스가 마비되어 버린 상황이에요.

이런 경험, 서버를 운영하는 분들이라면 한 번쯤은 겪어보셨을 거예요. 도커 컴포즈는 설정이 매우 간결하고 강력하지만, 그 간결함 뒤에는 엄격한 문법 규칙이 숨어 있어요. YAML이라는 포맷 특성상 눈에 잘 보이지 않는 공백 하나가 시스템 전체의 구조를 완전히 뒤틀어 놓을 수 있거든요. 단순한 오타가 단순히 컨테이너가 안 뜨는 문제를 넘어, 데이터가 통째로 사라지는 최악의 결과로 이어지기도 해요.

단순히 명령어를 외우는 것만으로는 부족해요. 운영 환경에서는 항상 ‘무엇이 잘못될 수 있는가’를 먼저 생각해야 하죠. 이번 글에서는 실제 현장에서 빈번하게 발생하는 docker compose yml 실수 패턴을 분석하고, 이를 예방하여 안정적인 컨테이너 운영을 할 수 있는 구체적인 방법을 알려드릴게요.

이 글을 다 읽고 나면 다음 내용들을 확실히 내 것으로 만들 수 있어요.

  • 가장 빈번하게 발생하는 문법적 오류와 해결 방법
  • 데이터 유실을 막기 위한 안전한 볼륨 설정법
  • 환경 변수와 네트워크 설정 시 주의해야 할 핵심 포인트
  • 실수를 사전에 차단하는 검증 프로세스 구축 방법

실수를 줄이기 위한 사전 준비와 핵심 규칙

설정 파일을 작성하기 전에 먼저 우리가 다루는 도구의 특성을 명확히 이해해야 해요. docker compose yml 파일은 단순히 명령어를 나열하는 곳이 아니라, 인프라의 구조를 정의하는 설계도와 같아요. 설계도가 잘못되면 건물을 올릴 수 없듯이, 문법이 어긋나면 컨테이너는 절대로 정상적으로 동작하지 않아요.

가장 먼저 확인해야 할 것은 YAML 문법의 엄격함이에요. YAML은 사람이 읽기 편하도록 설계되었지만, 컴퓨터 입장에서는 매우 예민한 형식이에요. 특히 탭(Tab) 문자를 사용하면 안 된다는 점을 명심해야 해요. 반드시 스페이스(Space)를 사용해야 하며, 들여쓰기 단계가 일관되지 않으면 파서(Parser)가 파일 구조를 완전히 오해하게 돼요.

또한, 사용 중인 도커 엔진의 버전과 컴포즈 파일의 스펙 버전이 맞는지 확인하는 과정도 필수적이에요. 버전에 따라 사용할 수 있는 키(Key) 이름이 달라지거나, 특정 설정 방식이 지원되지 않을 수도 있거든요. 아래 표를 통해 설정 시 반드시 고려해야 할 기준들을 비교해 보세요.

구분 항목 권장되는 방식 위험한 방식
들여쓰기(Indentation) 스페이스 2칸 또는 4칸 고정 사용 Tab 키 혼용 또는 불규칙한 공백
이미지 태그(Tag) 특정 버전 명시 (예: nginx:1.25) latest 태그 사용
포트 설정(Ports) 따옴표로 감싼 문자열 형식 (“80:80”) 숫자 형식으로 직접 입력 (80:80)
환경 변수(Env) .env 파일 분리 및 관리 yml 파일 내에 직접 하드코딩
💡 알아두기
설정 파일을 작성하기 전에 VS Code와 같은 에디터에서 YAML 확장 프로그램을 반드시 설치하세요. 눈으로 보이지 않는 공백이나 탭 문자를 시각적으로 보여주어 실수를 획기적으로 줄여준답니다.

준비가 되었다면 이제 본격적으로 어떤 부분에서 실수가 발생하는지, 구체적인 단계별 사례를 통해 살펴보도록 해요. 단순한 오타를 찾는 수준을 넘어, 시스템의 안정성을 해치는 근본적인 패턴을 찾아내는 것이 목표예요.

안정적인 운영을 위한 단계별 설정 가이드

이제 실무에서 가장 많이 발생하는 문제들을 중심으로, 올바른 설정 방법과 주의사항을 단계별로 자세히 알아볼게요. 각 단계를 꼼꼼히 읽고 현재 여러분의 설정 파일과 비교해 보세요.

STEP 1. 들여쓰기와 공백의 늪 탈출하기

YAML에서 들여쓰기는 단순한 가독성 문제가 아니라 데이터의 계층 구조를 결정하는 결정적인 요소예요. 만약 services 항목 아래에 있는 컨테이너 설정이 한 칸이라도 어긋나면, 도커는 해당 설정을 서비스의 속성이 아니라 전혀 다른 상위 항목의 속성으로 오해하게 돼요.

가장 흔한 실수는 리스트를 나타내는 하이픈(-) 뒤에 공백을 넣지 않거나, 하이픈의 위치를 일관성 없이 배치하는 경우예요. 예를 들어, 환경 변수 목록을 작성할 때 어떤 것은 하이픈 뒤에 공백이 있고, 어떤 것은 없는 식의 실수가 잦아요. 이는 파싱 에러를 유발하거나, 최악의 경우 설정이 무시되는 결과를 초래해요.

⚠️ 주의
절대로 키(Key)와 값(Value) 사이에 콜론(:)을 쓰고 나서 공백을 한 칸 띄우지 마세요. key:value는 틀린 문법이며, 반드시 key: value와 같이 공백이 있어야 해요.

STEP 2. 환경 변수와 .env 파일의 충돌 방지

설정 파일 내부에 비밀번호나 API 키를 직접 적는 것은 보안상 매우 위험할 뿐만 아니라 관리 측면에서도 비효율적이에요. 그래서 대부분 env_file이나 environment 키를 사용하여 외부에서 값을 주입하죠. 여기서 발생하는 주요 실수는 우선순위 혼동이에요.

도커 컴포즈는 환경 변수를 주입하는 여러 경로가 있는데, 그 우선순위가 정해져 있어요. 만약 .env 파일에도 변수가 있고, docker-compose.ymlenvironment 섹션에도 동일한 변수가 있다면, environment에 적힌 값이 최종적으로 적용돼요. 개발 환경에서는 잘 작동하던 설정이 운영 환경에서 갑자기 바뀌어 버리는 이유가 바로 이 우선순위 때문인 경우가 많아요.

또한, 환경 변수 값에 특수 문자가 포함되어 있다면 반드시 따옴표로 감싸주어야 해요. 예를 들어, 비밀번호에 `#`이나 `$` 같은 문자가 포함되어 있으면 YAML 파서가 이를 주석이나 변수로 오해하여 값을 잘라버릴 수 있어요. 항상 문자열은 쌍따옴표(“)로 감싸는 습관을 들이는 것이 안전해요.

STEP 3. 데이터 유실을 막는 볼륨 마운트 전략

서버 관리자가 가장 두려워하는 상황은 컨테이너를 재시작하거나 업데이트했을 때 DB 데이터가 모두 사라지는 것이에요. 이는 대부분 볼륨(Volumes) 설정 실수에서 비롯돼요. 볼륨 설정에는 호스트의 경로를 직접 연결하는 ‘바인드 마운트’와 도커가 관리하는 ‘네임드 볼륨’ 두 가지 방식이 있어요.

바인드 마운트를 사용할 때 가장 자주 하는 실수는 상대 경로를 잘못 지정하는 것이에요. ./data:/var/lib/mysql과 같이 작성했을 때, docker compose 명령어를 실행하는 위치가 생각했던 곳과 다르면 데이터는 전혀 엉뚱한 폴더에 쌓이게 돼요. 결국 컨테이너를 새로 띄우면 이전 데이터는 어디에도 보이지 않는 마법 같은 일이 벌어지죠.

안정적인 운영을 위해서는 가급적 네임드 볼륨을 사용하는 것을 권장해요. 네임드 볼륨은 도커 엔진이 경로를 직접 관리하므로 경로 오타로 인한 데이터 유실 위험이 훨씬 적거든요. 만약 호스트의 특정 경로를 꼭 써야 한다면, 반드시 절대 경로를 사용하거나 실행 위치를 명확히 확인하는 절차가 필요해요.

STEP 4. 네트워크 격리와 통신 오류 해결

여러 컨테이너가 협력하여 작동할 때, 이들 사이의 통신은 네트워크(Networks) 설정에 의존해요. 기본적으로 도커 컴포즈는 모든 서비스를 하나의 기본 네트워크에 묶어주지만, 보안을 위해 서비스별로 네트워크를 분리하는 것이 좋아요. 이때 발생하는 흔한 실수는 컨테이너 이름으로 통신을 시도할 때 네트워크가 서로 격리되어 있어 이름을 찾지 못하는 경우예요.

예를 들어, 웹 서버(Web)와 데이터베이스(DB)가 각각 다른 사용자 정의 네트워크에 속해 있다면, 웹 서버는 DB의 서비스 이름을 통해 접근할 수 없어요. 이럴 때는 두 서비스가 공통으로 속한 공용 네트워크를 하나 더 만들어 연결해 주어야 해요. 네트워크 설정을 설계할 때는 ‘어떤 서비스가 어떤 서비스에게 말을 걸어야 하는가’를 미리 그려보는 과정이 반드시 선행되어야 해요.

STEP 5. 이미지 태그와 버전 관리의 중요성

마지막으로, 이미지 태그를 latest로 설정하는 습관을 반드시 버려야 해요. latest 태그는 ‘가장 최신’을 의미할 뿐, ‘안정적’임을 의미하지 않아요. 어느 날 갑자기 이미지가 업데이트되면서 기존과 호환되지 않는 환경이 구성되면, 서비스는 예고 없이 중단될 수 있어요.

실제로 운영 중인 서버에서는 반드시 nginx:1.25.3처럼 구체적인 버전을 명시해야 해요. 그래야만 새로운 서버로 이전하거나 설정을 재배포할 때, 모든 환경에서 동일한 동작을 보장할 수 있어요. 버전 관리는 단순히 버그를 막는 것이 아니라, 인프라의 재현 가능성(Reproducibility)을 확보하는 가장 기본적이고 중요한 작업이에요.

💡 알아두기
설정을 변경한 후에는 바로 docker compose up -d를 실행하기보다, docker compose config 명령어를 먼저 실행해 보세요. 이 명령어는 작성한 파일의 문법이 올바른지 검증하고, 최종적으로 적용될 설정값이 어떤 형태인지 미리 보여준답니다.

자주 하는 실수와 해결법 및 자주 묻는 질문

자주 하는 실수와 해결법

현장에서 즉시 적용할 수 있는 대표적인 실수 사례들을 정리했어요. 비슷한 문제를 겪고 있다면 이 해결법을 따라 해 보세요.

  • 포트 설정 시 숫자로만 입력함 (예: ports: - 80:80)
    왜 발생하는가: YAML 파서가 이를 숫자로 인식하여 문법 오류를 내거나 의도치 않은 형식으로 변환함
    해결법: "80:80"처럼 반드시 따옴표로 감싸서 문자열로 전달하세요.
  • 환경 변수에 특수 문자가 포함됨
    왜 발생하는가: $나 `#` 문자가 변수 치환이나 주석으로 오해받음
    해결법: password: "p@ss#word"와 같이 전체 값을 큰따옴표로 감싸세요.
  • 이미지 태그를 latest로 방치함
    왜 발생하는가: 업데이트 시 호환되지 않는 버전이 내려받아져 서비스 장애 발생
    해결법: nginx:1.25처럼 명확한 버전을 지정하세요.
  • 볼륨 경로 오타 또는 상대 경로 혼동
    왜 발생하는가: 데이터가 엉뚱한 곳에 저장되어 컨테이너 삭제 시 데이터 증발
    해결법: 가능하면 네임드 볼륨을 사용하거나, 절대 경로를 사용하여 명확히 지정하세요.
  • depends_on 만으로 서비스 실행 순서를 보장하려 함
    왜 발생하는가: 컨테이너가 ‘실행’된 것과 내부 애플리케이션이 ‘준비’된 것은 다르기 때문
    해결법: healthcheck 설정을 함께 사용하여 서비스가 완전히 준비되었는지 확인하세요.

자주 묻는 질문

Q. docker compose config 명령어가 왜 중요한가요?

작성한 YAML 파일이 문법적으로 유효한지, 그리고 환경 변수들이 제대로 치환되어 최종적으로 어떤 형태의 설정 파일이 만들어지는지 미리 확인할 수 있는 가장 안전한 방법이기 때문이에요. 실제 배포 전 필수 코스라고 생각하시면 돼요.

Q. .env 파일이 적용되지 않는 것 같아요. 무엇을 확인해야 하나요?
우선 docker-compose.yml 파일과 .env 파일이 같은 디렉토리에 있는지 확인해 보세요. 또한, 파일 내부에 오타가 없는지, 그리고 변수 이름이 대문자로 정확히 일치하는지 체크해야 해요.

Q. 볼륨을 연결했는데 호스트의 파일이 컨테이너 안에서 안 보여요.
경로 문제일 확률이 매우 높아요. 상대 경로를 썼다면 현재 명령어를 실행하는 위치를 확인하시고, 가급적 절대 경로를 사용하여 경로가 틀릴 여지를 없애는 것이 좋아요.

Q. 컨테이너끼리 통신이 안 되는데 네트워크 설정을 어떻게 해야 하나요?
두 서비스가 동일한 네트워크에 속해 있는지 확인하세요. 각 서비스 설정에 networks: 항목이 있고, 그 아래에 같은 네트워크 이름이 적혀 있어야 서로의 서비스 이름으로 통신이 가능해요.

Q. YAML 파일에서 탭(Tab)을 썼는데 오류가 나요.
YAML 표준은 탭 문자를 허용하지 않아요. 에디터 설정에서 ‘Tab을 Space로 변환’ 옵션을 켜거나, 모든 들여쓰기를 스페이스로 직접 교체해 보세요.

댓글 남기기