[IT-방법] 컴포즈 build 옵션 자동화와 CI/CD 연동 – 반복적인 빌드와 배포를 손에서 놓는 법

build 옵션과 빌드 컨텍스트를 설명하는 자동화와 CI/CD 연동 대표 이미지

반복되는 빌드 명령에서 벗어나야 하는 이유

퇴근 직전, 코드를 수정하고 배포를 준비하는데 갑자기 docker-compose up --build 명령어가 오류를 뱉어요. 빌드 컨텍스트에 포함되지 말아야 할 거대한 로그 파일이 포함되어 빌드 속도가 느려지거나, 빌드 인자(build args) 하나를 잘못 넘겨서 서버 환경이 꼬이는 경험을 해보셨을 거예요. 매번 터미널에 길고 복잡한 옵션을 직접 타이핑하는 것은 단순한 귀찮음을 넘어 휴먼 에러의 온상이 돼요.

수동으로 진행하는 배포는 항상 불안함을 동반해요. “내가 이번에 빌드 옵션을 제대로 넣었나?”, “환경 변수가 제대로 전달되었나?” 같은 의문이 머릿속을 떠나지 않죠. 규모가 작은 프로젝트라면 직접 입력하는 게 빠를지 몰라도, 서비스가 커지고 배포 횟수가 늘어나면 이 방식은 반드시 한계에 부딪혀요. 결국 자동화는 선택이 아니라 지속 가능한 운영을 위한 필수 생존 전략이에요.

이 글을 통해 컴포즈 build 옵션 자동화를 완벽하게 구현하는 흐름을 배워볼 거예요. 단순히 명령어를 자동화하는 것을 넘어, 빌드 컨텍스트를 최적화하고 CI/CD 파이프라인에 자연스럽게 녹여내는 실전 기술을 다뤄요. 글을 다 읽고 나면 더 이상 배포 명령어를 외우느라 고생하지 않아도 될 거예요.

오늘 함께 다룰 핵심 내용은 다음과 같아요.

  • 빌드 컨텍스트와 옵션의 정확한 개념 정리
  • 동적 빌드를 위한 build args 활용법
  • 스크립트와 CI/CD를 활용한 배포 자동화 설계
  • 빌드 오류 방지를 위한 검증 및 롤백 전략

자동화를 시작하기 전 반드시 챙겨야 할 기본 지식

자동화 도구를 만들기 전에 도커 컴포즈가 빌드를 어떻게 처리하는지 명확히 알아야 해요. 무턱대고 스크립트부터 짜다가는 오히려 디버깅이 더 힘든 스파게티 코드를 만들 수 있어요. 먼저 빌드 컨텍스트(Build Context)가 무엇인지 이해하는 것이 첫걸음이에요. 빌드 컨텍스트는 도커 데몬에게 전달되는 파일들의 범위예요. 이 범위가 너무 넓으면 빌드 속도가 느려지고, 너무 좁으면 필요한 파일을 찾지 못해 오류가 발생해요.

또한, 빌드 시점에만 필요한 값과 컨테이너가 실행된 후 필요한 값의 차이를 구분해야 해요. 빌드 시점에는 args를 사용하고, 실행 시점에는 environment를 사용한다는 원칙을 잊지 마세요. 이 둘을 혼동하면 빌드 이미지는 성공해도 실제 서비스가 구동되지 않는 황당한 상황을 맞이하게 돼요.

💡 알아두기
빌드 옵션을 자동화할 때는 항상 .dockerignore 파일을 함께 관리해야 해요. 불필요한 데이터가 빌드 컨텍스트에 포함되는 것을 막는 가장 효과적인 방법이기 때문이에요.

자동화 수준을 결정하기 위해 아래 비교 표를 참고해서 현재 우리 팀의 상황에 맞는 목표를 설정해 보세요.

자동화 단계 주요 방식 장점 단점
기초 단계 쉘 스크립트(.sh) 구현이 매우 빠름 복잡한 로직 관리 어려움
중급 단계 Makefiles 활용 명령어 체계화 가능 학습 곡선 존재
고급 단계 CI/CD 파이프라인 완전 자동화 및 검증 초기 설정 비용 높음

어떤 방식을 선택하든 핵심은 ‘재현 가능성’이에요. 누가, 어디서, 언제 실행해도 동일한 빌드 결과물이 나와야 자동화의 가치가 있어요. 환경에 따라 달라지는 값들은 모두 외부에서 주입받을 수 있도록 설계해야 해요.

컴포즈 빌드 자동화 실전 실행 단계

이제 이론을 넘어 실제로 어떻게 자동화를 구축하는지 단계별로 살펴볼게요. 단순한 명령 실행을 넘어, 관리하기 쉬운 구조를 만드는 데 집중해 주세요.

STEP 1. 빌드 컨텍스트와 Dockerfile 정밀 설계

자동화의 첫 단추는 docker-compose.yml 파일 내에서 빌드 옵션을 명확히 정의하는 것이에요. 단순히 build: .이라고 쓰는 습관을 버려야 해요. 프로젝트 구조가 복잡해질수록 컨텍스트를 제한하는 것이 유리해요.

예를 들어, 특정 서비스의 소스 코드가 ./services/api 폴더에 있다면 컨텍스트를 해당 폴더로 한정하세요. 이렇게 하면 도커 데몬이 빌드를 위해 전송해야 하는 파일 용량이 획기적으로 줄어들어요. 또한, dockerfile: ./services/api/Dockerfile 옵션을 통해 도커파일의 위치를 명시적으로 지정해 주세요. 이렇게 하면 나중에 파일 위치가 바뀌더라도 자동화 스크립트를 일일이 수정할 필요가 없어요.

이 단계에서 반드시 .dockerignore 파일을 작성하세요. node_modules, .git, dist, *.log 같은 파일들을 제외하지 않으면, 코드를 한 줄만 바꿔도 빌드 캐시가 깨져서 매번 모든 레이어를 다시 빌드하게 될 수도 있어요. 캐시 효율성이 곧 개발 속도라는 점을 기억하세요.

STEP 2. build args를 활용한 환경별 동적 빌드

운영(Production) 서버와 개발(Development) 서버의 빌드 설정이 다르다면 어떻게 해야 할까요? 매번 파일을 새로 쓰는 대신 args를 활용하세요. docker-compose.yml에 다음과 같이 작성할 수 있어요.

build:
  context: .
  args:
    APP_VERSION: "${APP_VERSION:-latest"}
    NODE_ENV: "${NODE_ENV:-development"}

이렇게 설정해 두면 쉘에서 환경 변수를 넘겨주는 것만으로도 빌드 시점에 값을 주입할 수 있어요. 빌드 중에 사용될 값은 Dockerfile 내에서 ARG APP_VERSION처럼 선언해야 한다는 사실도 잊지 마세요. 이 방식은 이미지를 여러 번 만들 필요 없이, 하나의 Dockerfile로 다양한 환경의 이미지를 생성할 수 있게 해줘요.

STEP 3. 쉘 스크립트를 이용한 빌드 로직 캡슐화

매번 긴 명령어를 입력하는 대신, 우리 팀만의 빌드 명령어를 만드세요. 예를 들어 ./deploy.sh build api라는 명령 하나로 모든 과정이 끝나도록 만드는 거예요. 스크립트 내부에는 다음과 같은 로직이 포함되어야 해요.

  • 현재 Git 브랜치 확인 및 최신 코드 Pull
  • 필요한 환경 변수 존재 여부 체크
  • docker-compose build 실행
  • 빌드 성공 여부에 따른 다음 단계 결정

단순히 명령어를 나열하는 게 아니라, 조건문을 활용해 오류를 잡아내는 것이 핵심이에요. 빌드가 실패했을 때 기존 컨테이너를 건드리지 않고 즉시 중단하는 로직이 반드시 들어가야 서비스 중단을 막을 수 있어요.

STEP 4. CI/CD 파이프라인 연동하기

이제 스크립트를 GitHub Actions나 GitLab CI 같은 도구에 이식할 차례예요. CI/CD 연동의 핵심은 ‘사람의 개입을 최소화하는 것’이에요. GitHub Actions를 기준으로 본다면, 코드가 메인 브랜치에 Push될 때 자동으로 트리거되도록 설정하세요.

워크플로우 파일(.yml)에는 빌드 단계를 명시하고, 빌드가 완료된 이미지를 Docker Registry(Docker Hub, ECR 등)에 Push하는 과정까지 포함시켜야 해요. 이때 build-push-action 같은 검증된 액션을 사용하면 훨씬 안정적으로 운영할 수 있어요.

💡 알아두기
CI 환경에서는 빌드 속도를 위해 Layer Caching 설정을 반드시 추가하세요. 이전 빌드에서 사용한 레이어를 재사용하면 CI 실행 시간을 절반 이하로 줄일 수 있어요.

STEP 5. 빌드 결과물 검증 및 자동 롤백 설계

빌드가 성공했다고 해서 배포가 끝난 건 아니에요. 배포된 컨테이너가 정상적으로 동작하는지 확인하는 Health Check 단계가 필요해요. docker-compose.ymlhealthcheck 옵션을 사용해 컨테이너가 ‘healthy’ 상태가 될 때까지 기다리는 로직을 자동화 스크립트에 포함하세요.

만약 헬스 체크에 실패한다면? 바로 이전 버전의 이미지로 되돌리는 롤백 시나리오를 짜두어야 해요. docker-compose up -d --remove-orphans 명령과 함께 이전 태그의 이미지를 사용하는 스크립트를 준비해 두면, 새벽에 장애가 발생해도 잠을 잘 수 있는 환경이 만들어져요.

⚠️ 주의
자동화된 롤백 스크립트가 잘못 작동하면 오히려 서비스가 완전히 중단될 수 있어요. 반드시 테스트 환경에서 롤백 시나리오를 최소 5회 이상 반복 테스트한 뒤 운영 환경에 적용하세요.

자주 하는 실수와 해결법

자동화를 구축하다 보면 예상치 못한 난관에 부딪히곤 해요. 가장 흔히 발생하는 실수 5가지를 정리했으니, 비슷한 문제를 겪고 있다면 확인해 보세요.

  • 빌드 컨텍스트가 너무 커서 속도가 느려짐
    → 왜 발생하는가: .dockerignore를 설정하지 않아 불필요한 데이터까지 전송됨
    ✅ 해결법: 프로젝트 루트에 .dockerignore를 만들고 대용량 폴더와 로그를 반드시 제외하세요.
  • 빌드 시점에 입력한 변수가 실행 시점에 사라짐
    → 왜 발생하는가: ARGENV의 생명주기를 혼동함
    ✅ 해결법: 빌드용은 ARG, 실행용은 ENV를 사용하고, 빌드 후 값이 필요하면 ENV로 다시 넘겨주세요.
  • CI/CD에서 캐시가 작동하지 않음
    → 왜 발생하는가: 매번 새로운 환경에서 빌드가 이루어져 레이어 공유가 안 됨
    ✅ 해결법: CI 설정에서 외부 캐시(Registry Cache)를 사용하도록 명시하세요.
  • 민감한 정보가 이미지 레이어에 노출됨
    → 왜 발생하는가: API 키나 비밀번호를 build args로 넘김
    ✅ 해결법: 민감 정보는 빌드 시점이 아닌 실행 시점에 secrets나 환경 변수로 주입하세요.
  • 배포 후 컨테이너가 무한 재시작됨
    → 왜 발생하는가: 빌드는 성공했지만 애플리케이션 내부 설정 오류가 있음
    ✅ 해결법: healthcheck를 도입하고, 배포 전 단계에서 유닛 테스트와 통합 테스트를 수행하세요.

자주 묻는 질문

Q. 도커 컴포즈 빌드 옵션을 CLI 명령어로 직접 수정할 수 있나요?

네, 가능해요. docker-compose build --build-arg KEY=VALUE 형식을 사용하면 yml 파일을 수정하지 않고도 실행 시점에 특정 인자를 넘길 수 있어요. 자동화 스크립트에서 이 방식을 활용하면 매우 유연한 대응이 가능해요.

Q. 하나의 Dockerfile로 여러 서비스를 관리할 수 있을까요?

가능하지만 권장하지는 않아요. 서비스마다 필요한 종속성이 다르기 때문에, 서비스별로 Dockerfile을 따로 두는 것이 빌드 속도와 이미지 최적화 측면에서 훨씬 유리해요. 굳이 합치고 싶다면 멀티 스테이지 빌드(Multi-stage build)를 활용하는 것이 정석이에요.

Q. 빌드 컨텍스트를 특정 폴더로 지정하면 상위 폴더의 파일은 못 쓰나요?

맞아요. 도커의 보안 설계상 빌드 컨텍스트로 지정된 폴더와 그 하위 파일에만 접근할 수 있어요. 상위 폴더의 파일이 필요하다면 컨텍스트 자체를 프로젝트 루트로 잡아야 해요. 대신 .dockerignore로 필요한 파일만 남기는 전략을 쓰세요.

Q. CI/CD 연동 시 이미지 태그는 어떻게 관리하는 게 좋을까요?

latest 태그는 지양하세요. 대신 Git 커밋 해시(Commit Hash)나 시맨틱 버저닝(Semantic Versioning)을 사용하는 것이 좋아요. 그래야 문제가 생겼을 때 정확히 어떤 버전에서 오류가 났는지 파악하고 롤백할 수 있어요.

댓글 남기기