[IT-방법] 컴포즈 build 옵션 자동화와 CI/CD 연동 – 반복되는 배포 작업을 멈추는 실무 가이드

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

매번 반복되는 수동 빌드의 늪에서 벗어나는 법

새로운 코드를 작성하고 서버에 반영하려고 터미널을 켰을 때, 익숙한 긴 명령어를 복사해서 붙여넣고 있지는 않으신가요? 도커 컴포즈 build 옵션 자동화가 되어 있지 않으면, 개발자는 매번 `–build-arg` 뒤에 복잡한 인자들을 수동으로 입력해야 해요. 이 과정에서 오타 하나만 발생해도 빌드는 실패하고, 서버는 엉뚱한 환경 설정을 물고 올라가 버리죠.

특히 서비스 규모가 커지면서 여러 개의 컨테이너를 관리하게 되면 상황은 더 심각해져요. 어떤 서비스는 특정 버전의 API 키가 필요하고, 어떤 서비스는 운영 환경 전용 라이브러리를 빌드 시점에 주입해야 해요. 이걸 일일이 기억해서 명령어를 치는 건 사람이 할 일이 아니라 기계가 해야 할 일이에요. 결국 사람이 하는 일에는 실수가 따를 수밖에 없고, 이는 곧 서비스 장애로 이어지기도 해요.

우리는 이제 단순한 배포를 넘어, 빌드 컨텍스트를 최적화하고 실행 과정을 스크립트로 묶는 단계로 넘어가야 해요. 단순히 명령어를 대신 입력해 주는 것을 넘어, 어떤 파일이 빌드에 포함될지, 어떤 환경 변수가 주입될지를 시스템이 스스로 판단하게 만들어야 하죠. 그래야만 퇴근 직전의 불안함 없이 코드를 밀어 넣을 수 있어요.

이 글을 끝까지 읽고 나면, 여러분은 다음과 같은 능력을 갖추게 될 거예요.

  • 빌드 속도를 획기적으로 줄여주는 빌드 컨텍스트 최적화 방법
  • 복잡한 명령어를 한 줄로 줄여주는 환경 변수 및 스크립트 활용법
  • 사람의 개입 없이도 안전하게 동작하는 CI/CD 파이프라인 설계 노하우
  • 배포 실패 시 즉시 이전 상태로 되돌리는 롤백 전략

자동화를 시작하기 전 반드시 짚고 넘어가야 할 개념

무작정 스크립트를 짜기 전에, 우리가 무엇을 자동화하려 하는지 명확히 정의해야 해요. build context(빌드 컨텍스트)라는 개념을 먼저 이해해야 하는데요. 이건 도커가 빌드를 수행할 때 참조하는 파일들의 범위를 말해요. 만약 이 범위를 너무 넓게 잡으면, 필요 없는 수 기가바이트(GB)의 데이터까지 도커 엔진으로 전송되어 빌드 시간이 엄청나게 길어질 수 있어요.

또한 build option(빌드 옵션)은 빌드 시점에 컨테이너 내부로 값을 전달하는 통로예요. 예를 들어, 빌드할 때만 필요한 인증 토큰이나 개발 모드 여부를 결정하는 변수들을 이 옵션을 통해 넘겨주게 되죠. 이 두 가지를 제대로 제어하지 못하면 자동화를 하더라도 ‘느린 자동화’ 혹은 ‘불완전한 자동화’가 되어버려요.

💡 알아두기
빌드 컨텍스트를 줄이는 가장 쉬운 방법은 .dockerignore 파일을 사용하는 것이에요. 소스 코드 외에 로그 파일, 로컬 설정 파일, .git 폴더 등을 제외하는 것만으로도 빌드 성능이 눈에 띄게 좋아져요.

그럼 현재 여러분의 배포 방식은 어느 단계에 있는지 아래 표를 통해 확인해 보세요. 어느 단계로 나아가야 할지 판단하는 기준이 될 거예요.

구분 수동 방식 (Manual) 스크립트 방식 (Scripted) CI/CD 연동 (Automated)
명령어 입력 매번 직접 타이핑 쉘 스크립트 실행 이벤트 발생 시 자동 실행
환경 변수 관리 기억력에 의존 .env 파일 활용 Secret 관리 도구 활용
빌드 속도 느리고 비효율적 최적화 가능 캐시 활용으로 매우 빠름
장애 대응 즉각적 수동 조치 스크립트로 재시도 자동 롤백 시스템 작동

대부분의 개발자는 수동 방식에서 스크립트 방식으로 넘어가는 과정에서 가장 큰 효율을 느껴요. 하지만 진정한 컨테이너 운영의 안정성을 확보하려면 CI/CD 연동까지 완벽하게 마쳐야 해요. 이제 본격적으로 어떻게 자동화를 설계할지 단계별로 살펴볼게요.

실무에 바로 적용하는 단계별 자동화 설계 가이드

자동화는 단순히 명령어를 묶는 것이 아니라, 시스템이 스스로 판단할 수 있는 구조를 만드는 과정이에요. 다음 5가지 단계를 따라가며 여러분의 배포 환경을 업그레이드해 보세요.

STEP 1. 빌드 컨텍스트 다이어트하기

가장 먼저 해야 할 일은 도커에게 전달할 데이터의 양을 최소화하는 것이에요. 빌드할 때 프로젝트 폴더 전체를 넘기는 것은 매우 위험해요. 예를 들어, 프로젝트 안에 거대한 데이터셋이나 수천 개의 로그 파일이 있다면, 도커는 빌드를 시작하기도 전에 이 파일들을 전부 압축해서 도커 데몬으로 보내느라 엄청난 시간을 허비하게 돼요.

주의: 빌드 컨텍스트가 커지면 네트워크 부하가 생길 뿐만 아니라, 빌드 과정에서 의도치 않게 민감한 파일이 컨테이너 내부로 복사될 위험이 있어요.

이를 해결하기 위해 반드시 .dockerignore 파일을 작성해야 해요. 아래는 일반적인 웹 서비스 프로젝트에서 권장하는 제외 항목이에요.

  • node_modules/ (패키지 매니저가 빌드 시점에 새로 설치하도록 유도)
  • .git/ (버전 관리 이력은 빌드에 필요 없음)
  • *.log (로그 파일 제외)
  • dist/ 또는 build/ (이미 빌드된 결과물은 소스 코드와 충돌할 수 있음)
  • .env (로컬 설정 파일 유출 방지)

이렇게 컨텍스트를 깔끔하게 정리하면, 빌드 시작 속도가 수십 초 단위로 단축되는 것을 경험할 수 있어요.

STEP 2. .env 파일과 build-arg 연동하기

매번 명령어를 칠 때마다 `–build-arg VERSION=1.2.3` 같은 옵션을 넣는 건 정말 번거로운 일이에요. 이를 자동화하려면 docker-compose.yml 파일의 구조를 스마트하게 설계해야 해요. 컴포즈 파일 내부에 직접 값을 적지 말고, 환경 변수를 참조하도록 만드세요.

예를 들어, 컴포즈 파일은 다음과 같이 작성할 수 있어요.

services:
web:
build:
context: .
args:
- APP_VERSION=${APP_VERSION}
- BUILD_ENV=${BUILD_ENV}

이렇게 설정해 두면, 실제 명령어는 아주 간단해져요. 프로젝트 루트에 있는 `.env` 파일에 `APP_VERSION=1.2.3`이라고 적어두기만 하면, 컴포즈가 알아서 그 값을 읽어 빌드 옵션으로 넣어주거든요. 개발자는 이제 `.env` 파일만 관리하면 될 뿐, 길고 복잡한 명령어를 외울 필요가 없어요.

STEP 3. 쉘 스크립트로 빌드 워크플로우 캡슐화하기

환경 변수 설정과 빌드 명령어가 결합되면, 이제 이를 하나의 실행 파일로 만들어야 해요. 단순한 명령어가 아니라, 빌드-확인-실행이라는 논리적 흐름을 가진 스크립트를 만드는 것이죠. 예를 들어 `deploy.sh`라는 파일을 만들어 다음과 같은 로직을 담아보세요.

먼저, 스크립트는 현재 Git 브랜치가 배포 가능한 상태인지 체크해야 해요. 그 다음, 기존의 사용하지 않는 이미지들을 정리(prune)하여 디스크 공간을 확보하고, 새로운 버전으로 빌드를 시작하죠. 빌드가 성공하면 `docker-compose up -d`를 실행하고, 마지막으로 서비스가 정상적으로 올라왔는지 `curl` 명령어로 헬스 체크를 수행하는 구조예요.

이런 스크립트가 있으면, 팀원 모두가 동일한 환경에서 동일한 절차로 배포를 진행할 수 있어요. “내 컴퓨터에서는 됐는데 서버에서는 왜 안 되지?”라는 질문이 사라지는 마법을 경험하게 될 거예요.

STEP 4. CI/CD 파이프라인으로 확장하기

이제 로컬에서 만든 스크립트를 클라우드 환경으로 옮길 차례예요. GitHub Actions나 GitLab CI/CD 같은 도구를 사용하면, 코드가 메인 브랜치에 머지되는 순간 자동으로 배포가 시작돼요.

이 단계에서 가장 중요한 것은 보안이에요. API 키나 데이터베이스 비밀번호 같은 민감한 정보를 스크립트나 코드에 직접 적어두는 것은 자살 행위와 같아요. CI/CD 도구에서 제공하는 ‘Secrets’ 기능을 사용하여 변수를 관리하고, 빌드 시점에만 주입되도록 설계해야 해요.

전형적인 CI/CD 흐름은 이렇습니다. 1) 코드 푸시 2) 유닛 테스트 실행 3) 도커 이미지 빌드 4) 이미지 레지스트리(Docker Hub, ECR 등)로 푸시 5) 운영 서버에 배포 명령 전달. 이 과정이 자동화되면 개발자는 오직 코드 작성에만 집중할 수 있어요.

STEP 5. 자동화된 검증과 롤백 전략 구축

자동화의 완성은 ‘실패했을 때 어떻게 할 것인가’에 달려 있어요. 빌드가 성공했다고 해서 배포가 성공한 것은 아니에요. 컨테이너는 떴지만, 실제 API 호출 시 500 에러가 날 수도 있거든요.

따라서 반드시 Health Check 단계를 자동화에 포함해야 해요. 컴포즈 파일의 `healthcheck` 옵션을 활용하여 컨테이너가 ‘Running’ 상태를 넘어 ‘Healthy’ 상태가 되었는지 확인하는 로직을 넣으세요. 만약 헬스 체크에 실패하면, 스크립트가 즉시 이전 버전의 이미지를 사용하여 다시 실행하도록 설계해야 해요.

⚠️ 주의
롤백 전략이 없는 자동화는 오히려 독이 될 수 있어요. 잘못된 코드가 자동으로 배포되고, 그것이 즉시 서비스 장애로 이어지는 상황을 막기 위해 반드시 이전 이미지 태그를 보관하는 전략을 세우세요.

이 5단계를 모두 거친다면, 여러분의 배포 환경은 더 이상 불안한 도박이 아니라 신뢰할 수 있는 시스템이 될 거예요.

자주 하는 실수와 해결법

자동화 시스템을 구축하다 보면 예상치 못한 벽에 부딪히곤 해요. 실무에서 가장 자주 발생하는 문제들과 그 해결책을 정리해 두었으니 참고해 보세요.

  • 빌드 속도가 너무 느려요.
    왜 발생할까: 빌드 컨텍스트에 불필요한 대용량 파일이 포함되어 도커 엔진으로 전송되는 시간이 길어지기 때문이에요.
    ✅ 해결법: .dockerignore 파일을 작성하여 용량이 큰 폴더와 파일을 제외하세요.
  • 빌드 옵션으로 넘긴 변수가 적용되지 않아요.
    왜 발생할까: Dockerfile에서 ARG 명령어를 사용하여 변수를 선언하지 않았기 때문이에요. 컴포즈에서 넘겨준 값은 Dockerfile의 ARG를 거쳐 ENV로 전달되어야 해요.
    ✅ 해결법: Dockerfile 상단에 ARG 변수명을 반드시 명시하세요.
  • 서버 용량이 금방 가득 차버려요.
    왜 발생할까: 빌드할 때마다 생성되는 중간 이미지와 사용하지 않는 오래된 이미지들이 쌓이고 있기 때문이에요.
    ✅ 해결법: 배포 스크립트 마지막 단계에 docker image prune -f 명령어를 넣어 불필요한 이미지를 자동 삭제하세요.
  • CI/CD 환경에서 환경 변수를 못 읽어와요.
    왜 발생할까: 로컬의 .env 파일은 보안상 Git에 포함되지 않기 때문에 CI 서버에는 존재하지 않기 때문이에요.
    ✅ 해결법: CI/CD 도구(GitHub Actions 등)의 Secret 설정에 변수를 등록하고, 빌드 단계에서 이를 생성하도록 구성하세요.
  • 배포 후 서비스가 먹통이 되었는데 복구가 안 돼요.
    왜 발생할까: 자동화 시스템에 이전 버전으로 되돌리는 로직이 없기 때문이에요.
    ✅ 해결법: 이미지 태그에 항상 버전(예: v1.0.1)을 부여하고, 실패 시 해당 태그로 다시 실행하는 롤백 스크립트를 만드세요.

자주 묻는 질문

Q. 빌드 시 캐시를 강제로 사용하지 않고 새로 빌드하려면 어떻게 하나요?

A. docker-compose build --no-cache 옵션을 사용하면 됩니다. 코드 변경사항이 제대로 반영되지 않을 때 유용하지만, 빌드 시간이 길어지므로 꼭 필요한 경우에만 사용하세요.

Q. 보안을 위해 build-arg 사용을 피해야 한다고 들었는데 사실인가요?
A. 네, 맞아요. 빌드 인자는 이미지 레이어에 기록되기 때문에, 민감한 정보를 넣으면 이미지 내에서 누구나 볼 수 있어요. 비밀번호나 API 키는 빌드 시점이 아닌, 컨테이너가 실행되는 시점(Runtime)에 환경 변수로 주입하는 것이 훨씬 안전해요.

Q. .env 파일이 너무 많아지면 어떻게 관리하는 게 좋을까요?
A. 서비스 규모가 커지면 중앙 집중형 설정 관리 도구(예: AWS Parameter Store, HashiCorp Vault)를 사용하는 것이 좋아요. 스크립트가 실행될 때 이 도구로부터 값을 가져와서 .env를 생성하게 만들면 관리가 훨씬 쉬워져요.

Q. 여러 개의 컴포즈 파일을 동시에 사용해도 자동화가 가능한가요?
A. 당연하죠. docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d 처럼 여러 파일을 지정할 수 있어요. 자동화 스크립트에서 이 파일 목록을 변수로 관리하면 됩니다.

배포의 자유를 얻기 위한 마지막 체크리스트

지금까지 살펴본 자동화 과정은 단순히 편해지기 위한 것이 아니라, 서비스의 안정성을 담보하기 위한 필수적인 투자예요. 처음에는 스크립트 하나를 만드는 것도 막막할 수 있지만, 작은 명령어 하나부터 자동화하다 보면 어느덧 시스템이 알아서 돌아가는 모습을 보게 될 거예요.

✅ 핵심 요약

  • .dockerignore 활용: 빌드 컨텍스트를 최소화하여 속도와 보안을 동시에 잡으세요.
  • 환경 변수 체계화: 컴포즈 파일과 .env, 그리고 Dockerfile의 ARG를 유기적으로 연결하세요.
  • 워크플로우 캡슐화: 단순 명령어가 아닌, 검증 로직이 포함된 쉘 스크립트를 만드세요.
  • CI/CD 통합: 코드 머지 시 자동으로 빌드와 배포가 시작되도록 파이프라인을 구축하세요.
  • 안전장치 마련: 헬스 체크와 자동 롤백 전략을 반드시 포함하세요.

오늘 바로 무엇부터 시작해야 할지 고민된다면, 가장 먼저 여러분이 매일 입력하는 가장 길고 복잡한 명령어 하나를 골라 쉘 스크립트로 옮기는 것부터 시작해 보세요. 그 작은 시작이 여러분의 퇴근 시간을 앞당겨 줄 거예요.

다음 단계로 나아가고 싶다면, 이번 주에는 CI/CD 도구의 기초적인 파이프라인을 하나 설계해 보는 것을 추천해 드려요. 한 번에 모든 것을 바꾸려 하지 말고, 하나씩 자동화 영역을 넓혀가세요.

더 자세한 컨테이너 기초가 궁금하다면 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드 글을 함께 읽어보시면 큰 도움이 될 거예요.

댓글 남기기