[IT-정보] 컴포즈 build 옵션 정리 – 빌드 컨텍스트 이해와 효율적인 컨테이너 구축

build 옵션과 빌드 컨텍스트를 설명하는 완벽 정리 대표 이미지

왜 빌드 명령어가 실행될 때마다 오류가 발생할까요

새벽 2시, 배포를 위해 터미널에 명령어를 입력했는데 뜬금없는 “file not found” 메시지를 마주한 적이 있으신가요? 분명히 로컬 폴더에는 파일이 존재하는데, 도커 컴포즈는 마치 세상에 존재하지 않는 파일인 것처럼 행동합니다. 이 당혹스러운 순간은 대개 빌드 컨텍스트(Build Context)를 제대로 설정하지 않았을 때 발생해요.

도커를 막 도입한 서버 운영자나 백엔드 개발자라면 누구나 한 번쯤 겪는 문제입니다. 단순히 파일을 복사하는 과정을 넘어, 어떤 파일이 도커 엔진으로 전달되고 어떤 파일이 차단되는지를 이해하지 못하면 빌드 시간은 끝없이 길어지고 배포 환경은 불안정해질 수밖에 없어요. 효율적인 컨테이너 운영을 위해서는 이 기본 원리를 명확히 파악하는 것이 무엇보다 중요합니다.

오늘 이 글에서는 컴포즈 build 옵션 정리를 통해 여러분의 삽질 시간을 획기적으로 줄여드릴게요. 단순히 명령어만 나열하는 것이 아니라, 내부에서 어떤 일이 벌어지는지 그 흐름을 깊이 있게 다룰 예정이에요. 이 글을 다 읽고 나면 더 이상 경로 문제로 고통받지 않고, 최적화된 빌드 환경을 직접 구축할 수 있게 될 거예요.

💡 알아두기
도커 컴포즈는 여러 컨테이너의 설정을 관리하는 도구이지만, 그 안의 build 옵션은 개별 이미지의 설계도인 Dockerfile을 어떻게 가져와서 빌드할지를 결정하는 핵심적인 역할을 수행해요.

이 글에서 함께 살펴볼 내용들

  • 빌드 컨텍스트와 Dockerfile의 상관관계
  • 실무에서 바로 쓰는 docker-compose.yml 설정 예시
  • 빌드 속도를 높이는 최적화 전략
  • 자주 발생하는 경로 및 인자(args) 오류 해결법

빌드를 시작하기 전 반드시 이해해야 할 핵심 개념

무턱대고 설정을 바꾸기 전에, 우리가 다루는 용어들이 실제로 무엇을 의미하는지 정확히 짚고 넘어가야 해요. 도커 빌드 과정은 단순히 파일을 모으는 과정이 아니라, 클라이언트와 서버 사이의 데이터 전송 과정이기 때문이에요.

가장 먼저 이해해야 할 것은 빌드 컨텍스트(Build Context)예요. 우리가 특정 디렉토리를 빌드 컨텍스트로 지정하면, 도커 클라이언트는 그 디렉토리 안에 있는 모든 파일을 압축해서 도커 데몬(엔진)에게 통째로 보냅니다. 만약 이 폴더에 불필요하게 큰 로그 파일이나 데이터베이스 파일이 들어있다면, 빌드를 시작할 때마다 엄청난 네트워크 부하와 시간이 소요되겠죠? 이것이 바로 우리가 컨텍스트 범위를 좁혀야 하는 이유예요.

그다음으로는 Dockerfile이 있어요. 이것은 빌드 컨텍스트라는 상자 안에 들어있는 ‘조리법’과 같아요. 컨텍스트가 재료라면, Dockerfile은 그 재료를 어떻게 요리할지 적힌 설명서인 셈이죠. 여기서 주의할 점은 Dockerfile이 컨텍스트 외부에 있다면, 컨텍스트 옵션을 통해 그 위치를 명확히 알려줘야 한다는 사실이에요.

구분 항목 docker build (단일 빌드) docker-compose build (멀티 컨테이너)
주요 용도 단일 이미지 생성 시 사용 여러 서비스의 연관 빌드 관리
설정 방식 명령어 인자로 직접 지정 YAML 파일 내 build 섹션에 정의
복잡도 관리 수동 관리가 어려움 선언적 방식으로 관리 용이
추천 상황 테스트용 단일 이미지 실제 애플리케이션 배포 환경

이렇게 도커 빌드의 기본 원리를 이해했다면, 이제 실제 설정을 어떻게 작성해야 하는지 단계별로 알아볼 차례예요. 단순히 코드를 복사하는 게 아니라, 왜 이런 설정이 필요한지를 생각하며 읽어주세요.

⚠️ 주의
빌드 컨텍스트로 루트 디렉토리(/)를 지정하는 것은 매우 위험해요. 시스템의 모든 파일이 도커 엔진으로 전송되려 시도하면서 빌드 프로세스가 멈추거나 시스템 자원을 고갈시킬 수 있어요.

실무에서 바로 적용하는 컴포즈 빌드 설정 5단계

이제 본격적으로 컴포즈 build 옵션을 어떻게 구성해야 하는지 살펴볼게요. 실무 환경에서는 하나의 Dockerfile만 사용하는 경우보다, 환경별(dev, prod)로 다른 설정을 적용해야 하는 경우가 훨씬 많아요. 이를 위해 다섯 가지 핵심 단계를 제안합니다.

STEP 1. 빌드 컨텍스트와 Dockerfile 경로 분리하기

많은 개발자가 실수하는 부분 중 하나가 컨텍스트와 Dockerfile의 위치를 동일시하는 거예요. 하지만 실제로는 서비스의 소스 코드가 있는 폴더를 컨텍스트로 잡고, Dockerfile은 별도의 설정 폴더에 모아두는 것이 관리 측면에서 훨씬 유리해요. 예를 들어, 프로젝트 루트에 `docker/` 폴더를 만들고 그 안에 `Dockerfile.dev`, `Dockerfile.prod`를 두는 방식이죠.

이럴 때는 `docker-compose.yml`에서 다음과 같이 명시해야 해요. context는 소스 코드가 있는 곳을, dockerfile은 실제 파일의 상대 경로를 지정하는 것이 핵심이에요. 이렇게 하면 도커 엔진은 불필요한 파일을 건너뛰고 딱 필요한 소스 코드만 가져갈 수 있어요.

STEP 2. 빌드 인자(Build Arguments) 활용하기

빌드 시점에만 필요한 환경 변수가 있을 때가 있어요. 예를 들어, 특정 라이브러리의 버전을 결정하거나, 빌드 단계에서 사용할 API 키를 전달해야 하는 상황이죠. 이때 사용하는 것이 바로 args 옵션이에요. Dockerfile 내부에 `ARG` 명령어로 변수를 선언해두고, Compose 파일의 `build > args` 섹션에서 값을 넘겨주는 구조예요.

이 방식은 이미지 자체에 민감한 정보를 하드코딩하지 않아도 된다는 점에서 보안상 매우 유익해요. 다만, 빌드 인자로 넘긴 값은 이미지의 레이어 기록에 남을 수 있으므로, 실행 시점의 비밀번호 같은 민감 정보는 `args`가 아닌 `environment` 옵션을 사용해야 한다는 점을 꼭 기억하세요.

STEP 3. 멀티 스테이지 빌드와 타겟(Target) 지정하기

최근 트렌드는 멀티 스테이지 빌드를 사용하는 것이에요. 하나의 Dockerfile 안에 빌드용 스테이지와 실행용 스테이지를 나누어 작성하는 방식이죠. 이렇게 하면 최종 이미지에 컴파일러나 소스 코드 같은 무거운 파일들을 포함하지 않아 이미지 크기를 획기적으로 줄일 수 있어요.

도커 컴포즈에서는 `target` 옵션을 통해 특정 스테이지까지만 빌드하도록 명령할 수 있어요. 개발 단계에서는 디버깅 도구가 포함된 스테이지를, 운영 단계에서는 최적화된 최종 스테이지를 선택하도록 설정할 수 있어 매우 효율적이에요.

STEP 4. 실무형 docker-compose.yml 예시 살펴보기

앞서 설명한 내용들을 종합하여, 실제 현업에서 바로 사용할 수 있는 수준의 설정 예시를 준비했어요. 이 코드를 기반으로 여러분의 프로젝트에 맞게 수정해 보세요.

# docker-compose.yml 예시

services:
  web-app:
    build:
      # 1. 컨텍스트는 소스 코드가 있는 현재 디렉토리
      context: .
      # 2. Dockerfile의 위치를 별도 경로로 지정
      dockerfile: ./docker/Dockerfile.prod
      # 3. 빌드 시점에 넘겨줄 인자 설정
      args:
        NODE_ENV: production
        API_VERSION: v1
      # 4. 멀티 스테이지 중 최종 실행 단계만 타겟팅
      target: runner
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=db-service
      - DEBUG=false

위 설정에서 `web-app` 서비스는 `./docker/Dockerfile.prod`를 읽어오며, 빌드 과정에서 `NODE_ENV` 값을 `production`으로 받아들입니다. 최종적으로는 `runner`라는 이름의 스테이지까지만 빌드하여 실행 가능한 가벼운 이미지를 만들어내죠.

STEP 5. .dockerignore를 통한 빌드 최적화 마무리

아무리 설정을 잘해도 컨텍스트 자체에 쓰레기 데이터가 가득하면 소용없어요. `.dockerignore` 파일을 반드시 작성하세요. `node_modules`, `.git`, `dist`, 각종 로그 파일들을 이 파일에 등록해두면, 도커 클라이언트가 컨텍스트를 압축할 때 이 파일들을 제외합니다. 이는 빌드 속도 향상과 컨텍스트 크기 감소라는 두 마리 토끼를 잡는 가장 쉽고 강력한 방법이에요.

💡 알아두기
멀티 스테이지 빌드를 활용하면 이미지를 1GB에서 100MB 단위로 줄이는 것도 가능해요. 이는 배포 속도와 서버 저장 공간 관리 측면에서 엄청난 이득을 가져다줍니다.

자주 하는 실수와 해결법 및 FAQ

현장에서 발생하는 문제들은 대개 정해진 패턴이 있어요. 당황하지 말고 아래의 해결책을 하나씩 대조해 보세요.

자주 하는 실수와 해결법

  • 실수: “file not found” 에러가 발생해요.
    👉 원인: Dockerfile 내의 `COPY` 명령어가 참조하는 경로가 빌드 컨텍스트 외부에 있기 때문이에요.
    👉 해결법: 모든 파일은 반드시 설정한 `context` 디렉토리 내부로 이동시키거나, 컨텍스트 범위를 상위 디렉토리로 넓혀야 해요.
  • 실수: 빌드 인자(args)를 전달했는데 Dockerfile에서 인식을 못 해요.
    👉 원인: Dockerfile 안에 `ARG` 선언이 누락되었거나, `FROM`문 이전에 선언해야 하는 인자를 `FROM` 이후에 썼기 때문이에요.
    👉 해결법: Dockerfile 상단에 `ARG`를 명시하고, 사용하려는 시점에 맞춰 위치를 조정하세요.
  • 실수: 빌드 시간이 너무 오래 걸려요.
    👉 원인: 빌드 컨텍스트에 불필요한 대용량 파일(예: .git, node_modules)이 포함되어 전송 시간이 길어지고 있어요.
    👉 해결법: `.dockerignore` 파일을 생성하여 불필요한 파일을 즉시 제외하세요.
  • 실수: 코드를 수정했는데 반영이 안 되고 옛날 이미지가 실행돼요.
    👉 원인: 도커의 레이어 캐시 기능 때문이에요. 이전에 빌드된 레이어가 변경되지 않았다고 판단해 재사용하는 것이죠.
    👉 해결법: `docker-compose build –no-cache` 명령어를 사용하여 캐시를 무시하고 처음부터 다시 빌드하세요.
  • 실수: 컨테이너 실행 시 환경 변수가 작동하지 않아요.
    👉 원인: 빌드 시점에만 유효한 `args`를 실행 시점의 환경 변수로 착각한 경우예요.
    👉 해결법: 빌드 시 필요한 값은 `args`로, 실행 시 필요한 값은 `environment` 섹션에 작성하세요.

자주 묻는 질문

Q. 빌드 컨텍스트를 루트 디렉토리로 설정하면 안 되나요?
가급적 피하는 것이 좋아요. 루트로 설정하면 프로젝트 내의 모든 파일이 도커 데몬으로 전송되는데, 이는 빌드 성능을 심각하게 떨어뜨리고 보안상으로도 좋지 않은 습관이에요.

Q. Dockerfile이 여러 개일 때 어떻게 관리하는 게 가장 효율적인가요?
프로젝트 루트에 두기보다는 `docker/` 같은 별도 폴더에 환경별로(dev, prod, test) 관리하고, Compose 파일에서 `dockerfile` 경로를 각각 지정해 주는 방식이 가장 깔끔해요.

Q. 빌드 속도를 더 높일 수 있는 다른 방법이 있을까요?
Dockerfile 내에서 명령어 순서를 최적화하세요. 자주 바뀌지 않는 패키지 설치 명령(`npm install` 등)을 코드 복사(`COPY . .`)보다 앞순서에 배치하면, 코드가 바뀌어도 패키지 설치 레이어는 캐시를 사용할 수 있어요.

Q. docker-compose build와 docker-compose up –build의 차이는 무엇인가요?
`build`는 이미지만 새로 만드는 것이고, `up –build`는 빌드를 수행한 뒤 바로 컨테이너를 생성하고 실행까지 한 번에 진행하는 명령어예요. 개발 중에는 후자가 훨씬 편리하죠.

성공적인 컨테이너 운영을 위한 마지막 점검

지금까지 컴포즈 build 옵션 정리를 통해 빌드 컨텍스트와 다양한 설정법을 깊이 있게 살펴보았어요. 처음에는 복잡해 보일 수 있지만, 한 번 제대로 구조를 잡아두면 배포 자동화 과정이 놀라울 정도로 매끄러워질 거예요.

✅ 핵심 요약

  • 빌드 컨텍스트는 도커 엔진으로 전송되는 파일의 범위이므로 최소한으로 유지하세요.
  • Dockerfile의 위치와 context의 경로를 명확히 구분해서 설정하세요.
  • .dockerignore를 사용하여 빌드 속도와 보안을 동시에 잡으세요.
  • args는 빌드 시점에, environment는 실행 시점에 사용하세요.
  • 멀티 스테이지 빌드를 통해 이미지 크기를 최적화하는 습관을 들이세요.

오늘 배운 내용을 바탕으로 지금 바로 여러분의 프로젝트를 점검해 보세요. 작은 설정 하나가 서버의 안정성과 팀의 개발 생산성을 완전히 바꿔놓을 수 있습니다.

지금 바로 실행해 보세요

  • 오늘 할 일: 현재 프로젝트의 `.dockerignore` 파일이 있는지 확인하고, 불필요한 파일들을 등록하세요.
  • 이번 주 할 일: `docker-compose.yml`에 `target` 옵션을 도입하여 멀티 스테이지 빌드를 적용해 보세요.
  • 실행 직전 할 일: 테스트 서버에서 `–no-cache` 옵션을 사용해 빌드가 깨끗하게 수행되는지 최종 확인하세요.

설정 예시를 그대로 복사해 테스트 서버에서 먼저 실행해 보며 감을 익히는 것을 추천드려요. 더 궁금한 점이 있다면 관련 글을 통해 깊이를 더해 보세요.

도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드

댓글 남기기