[IT-방법] 컴포즈 파일 버전 자동화와 CI/CD 연동 – 반복적인 배포 작업을 줄이는 실무 기술

컴포즈 파일 버전 지정를 설명하는 자동화와 CI/CD 연동 대표 이미지

수동 배포의 늪에서 벗어나야 하는 이유

금요일 퇴근 직전, 평소처럼 도커 컴포즈로 서비스를 배포하려는데 무언가 이상해요. 분명히 코드는 수정했는데, 서버에는 예전 버전의 컨테이너가 그대로 돌아가고 있어요. 원인을 찾아보니 docker-compose.yml 파일의 버전 필드나 이미지 태그를 수정하는 것을 깜빡했네요. 이런 실수는 단순한 건망증이 아니라, 반복적인 수동 작업이 만들어낸 구조적인 문제입니다.

서비스 규모가 커지고 컨테이너 개수가 늘어날수록 사람이 직접 파일을 열어 숫자를 고치는 방식은 한계에 부딪혀요. 한 번의 실수가 전체 서비스 장애로 이어지기도 하고, 배포할 때마다 사람이 개입해야 하니 자동화된 파이프라인의 의미가 퇴색되죠. 컴포즈 파일 버전 자동화는 단순히 편해지기 위한 도구가 아니라, 배포의 안정성을 확보하기 위한 생존 전략이에요.

이제는 깃(Git)에 코드를 올리기만 하면, 시스템이 알아서 버전 번호를 계산하고 컴포즈 파일의 내용을 업데이트한 뒤 배포까지 마쳐야 해요. 사람이 개입하는 지점을 최소화할수록 배포 속도는 빨라지고 사고 확률은 급격히 낮아져요. 이 글에서는 반복적인 배포 작업에 지친 개발자를 위해, 컴포즈 파일 버전을 똑똑하게 관리하고 이를 CI/CD 환경에 녹여내는 구체적인 방법을 다뤄요.

오늘 함께 살펴볼 내용은 다음과 같아요.

  • 수동 배포 시 발생하는 주요 문제점과 자동화의 필요성
  • 버전 자동화를 위해 준비해야 할 도구와 환경
  • 스크립트와 CI 도구를 이용한 단계별 자동화 구현 방법
  • 배포 과정에서 흔히 겪는 오류와 해결책
  • 안정적인 운영을 위한 롤백 전략

자동화 환경 구축을 위한 사전 준비

무작정 스크립트를 짜기 전에, 우리 팀의 운영 환경이 자동화를 받아들일 준비가 되었는지 확인해야 해요. 자동화는 마법이 아니라, 잘 짜인 규칙과 도구의 조합이기 때문이에요. 무턱대고 도입했다가는 오히려 자동화된 오류가 더 빠르게 퍼지는 재앙을 맞이할 수도 있어요.

도구 선택과 환경 구성

가장 먼저 결정해야 할 것은 버전 관리 도구YAML 편집 도구예요. 단순히 텍스트를 치환하는 방식은 위험해요. YAML 파일은 구조가 중요한데, 단순한 텍스트 치환은 들여쓰기를 망가뜨려 파일을 깨뜨릴 수 있거든요. 그래서 구조를 이해하는 전문 도구가 필요해요.

💡 알아두기
YAML 파일은 들여쓰기에 매우 민감해요. 텍스트 편집기로 대충 수정하기보다는 yq 같은 전용 파서를 사용하는 것이 훨씬 안전하고 전문적인 방법이에요.

자동화 방식 비교하기

프로젝트의 복잡도에 따라 적절한 자동화 수준을 선택해야 해요. 모든 것을 한 번에 바꾸려 하기보다, 현재 상황에 맞는 단계를 밟아가는 것이 현명해요.

구분 수동 관리 스크립트 자동화 CI/CD 통합
작업 방식 직접 파일 수정 Shell/Python 스크립트 실행 코드 푸시 시 자동 실행
정확도 낮음 (실수 가능성 높음) 중간 (스크립트 오류 위험) 높음 (검증 단계 포함)
권장 대상 개인 프로젝트 소규모 팀 중대규모 운영 환경

핵심 체크리스트

자동화를 시작하기 전, 아래 조건들이 충족되었는지 반드시 점검해 보세요. 이 조건들이 갖춰지지 않으면 자동화는 오히려 관리 비용을 늘리는 짐이 될 뿐이에요.

  • Git 태그 전략: Semantic Versioning(예: v1.2.3) 규칙이 확립되어 있는가?
  • 환경 변수 관리: 버전 정보가 .env 파일이나 환경 변수로 주입될 준비가 되었는가?
  • 도구 설치: CI 서버(Runner)에 yq나 jq 같은 명령행 도구가 설치 가능한 환경인가?
  • 권한 체계: CI 도구가 컴포즈 파일을 수정하고 서버에 원격 명령을 내릴 권한이 있는가?

모든 준비가 끝났다면, 이제 실제로 파일을 어떻게 조작하고 배포 파이프라인에 태울지 구체적인 단계를 밟아볼까요?

컴포즈 파일 버전 자동화 실전 단계

이제 본격적으로 컴포즈 파일 버전 자동화를 구현해 봐요. 단순히 텍스트를 바꾸는 수준을 넘어, 실제 운영 환경에서 견고하게 작동하는 시스템을 만드는 과정이에요. 총 5단계의 과정을 통해 체계적으로 구축해 볼게요.

STEP 1. 버전 정보의 소스 정하기

자동화를 하려면 가장 먼저 “버전 정보가 어디서 오는가?”를 결정해야 해요. 버전 정보의 원천(Source of Truth)이 명확하지 않으면 자동화 프로세스가 꼬이게 돼요. 보통 다음 세 가지 중 하나를 선택해요.

  • Git Tag: 가장 권장하는 방식이에요. 개발자가 `git tag v1.0.5`를 생성하면, 이 태그 값이 컴포즈 파일의 버전이 돼요.
  • CI Build Number: Jenkins나 GitHub Actions에서 생성하는 고유 번호를 사용해요. 버전 관리가 엄격하지 않은 내부 테스트용 환경에 적합해요.
  • Timestamp: 배포 시점의 시간을 사용해요. 버전의 의미보다는 “언제 배포되었는가”가 더 중요할 때 유용해요.

실무에서는 Git Tag를 사용하는 것이 가장 좋아요. 코드가 어떤 버전인지와 배포된 컨테이너의 버전이 일치하기 때문에 추적 관리가 매우 쉽기 때문이에요.

STEP 2. yq를 활용한 YAML 구조적 수정

이제 결정한 버전 정보를 컴포즈 파일에 써넣어야 해요. 여기서 많은 개발자가 실수하는 것이 `sed` 명령어를 사용하는 거예요. `sed`는 텍스트를 바꾸는 데는 훌륭하지만, YAML의 계층 구조를 이해하지 못해요. 예를 들어, 여러 서비스에서 공통으로 쓰는 `version` 필드가 있을 때 `sed`는 엉뚱한 곳을 바꿀 위험이 커요.

가장 안전한 방법은 yq를 사용하는 거예요. `yq`는 YAML 전용 명령행 도구로, 파일의 구조를 유지하면서 특정 필드값만 정확하게 바꿀 수 있어요.

💡 알아두기
다음은 `yq`를 사용하여 `docker-compose.yml`의 `version` 필드를 업데이트하는 명령어 예시예요.
yq -i '.version = "3.8"' docker-compose.yml
이 명령어는 파일의 구조를 파괴하지 않고 딱 해당 필드만 안전하게 수정해 줘요.

STEP 3. CI/CD 파이프라인 설계하기

준비된 스크립트를 실제 배포 흐름에 녹여내야 해요. GitHub Actions를 기준으로 하는 표준적인 워크플로우 시나리오를 살펴볼게요. 이 과정은 사람이 직접 명령어를 치는 대신, 시스템이 흐름을 주도하게 만들어요.

  1. 트리거(Trigger): 개발자가 `main` 브랜치에 코드를 병합하거나 새로운 `tag`를 푸시할 때 파이프라인이 시작돼요.
  2. 체크아웃 및 도구 설치: 소스 코드를 가져오고, `yq`와 같은 필요한 도구들을 준비해요.
  3. 버전 추출: 현재의 Git 태그 값을 변수에 저장해요. (예: `TAG_NAME=$(git describe –tags)`)
  4. 파일 업데이트: 추출한 태그 값을 `yq`를 이용해 `docker-compose.yml`의 `version` 필드와 각 서비스의 `image` 태그에 주입해요.
  5. 이미지 빌드 및 푸시: 업데이트된 태그를 기반으로 도커 이미지를 빌드하고 레지스트리에 업로드해요.
  6. 원격 배포: SSH 등을 통해 서버에 접속하여 `docker compose up -d`를 실행해요.

STEP 4. 환경 변수(.env) 활용 전략

컴포즈 파일을 직접 수정하는 것이 부담스럽다면, 환경 변수 방식을 병행하는 것도 아주 좋은 전략이에요. 컴포즈 파일에는 변수명만 적어두고, 실제 값은 `.env` 파일에서 관리하는 거죠.

예를 들어, `docker-compose.yml` 파일 내용을 다음과 같이 구성할 수 있어요.

services:
  web:
    image: my-app:${APP_VERSION}
    labels:
      version: "${APP_VERSION}"

이렇게 해두면, 자동화 스크립트는 컴포즈 파일을 건드릴 필요 없이 `.env` 파일의 `APP_VERSION` 값만 한 줄 바꾸면 돼요. 파일 구조를 건드리지 않으니 훨씬 안전하고 관리가 쉬워져요. 실무에서는 이 방식을 가장 선호해요.

STEP 5. 배포 전 검증(Validation) 단계 추가

자동화가 끝났다고 바로 배포 버튼을 누르면 안 돼요. 자동화 스크립트가 실수로 파일을 망가뜨렸을 수도 있으니까요. 배포 직전에 반드시 검증 단계를 넣어야 해요.

가장 좋은 명령은 `docker compose config예요. 이 명령어를 실행하면 현재 작성된 컴포즈 파일이 문법적으로 올바른지, 변수 치환은 제대로 되었는지 확인하고 최종적으로 해석된 내용을 화면에 보여줘요. 이 과정에서 에러가 발생한다면 파이프라인을 즉시 중단시키고 배포를 막아야 해요. 검증 없는 자동화는 사고를 자동화하는 것과 같아요.

실무 적용 시나리오: 5분 완성 배포 흐름

실제 운영 환경에서 적용할 수 있는 통합 시나리오를 정리해 드릴게요. 이 순서대로 구축해 보세요.

  • 0분: 개발자가 기능 개발 완료 후 `v1.2.0` 태그를 달고 푸시함.
  • 1분: CI 서버가 태그를 감지하고 파이프라인 가동.
  • 2분: 스크립트가 `.env` 파일 내 `VERSION=1.2.0`으로 업데이트함.
  • 3분: 도커 이미지가 빌드되고 레지스트리에 `my-app:1.2.0`으로 저장됨.
  • 4분: 서버에서 `docker compose up -d`가 실행되며 새 버전 컨테이너가 뜸.
  • 5분: 헬스 체크(Health Check)를 통해 서비스 정상 동작 확인 후 종료.

자주 하는 실수와 해결법

자동화를 구축하다 보면 예상치 못한 곳에서 문제가 터지곤 해요. 경험 많은 엔지니어들도 종종 겪는 실수들을 정리했으니, 미리 체크해 보세요.

  • 실수: `sed` 명령어로 YAML 파일을 수정하다 들여쓰기가 깨짐
    왜 발생하는가: `sed`는 텍스트 기반이라 YAML의 계층 구조를 모른 채 단순히 글자만 바꿔버리기 때문이에요.
    → ✅ 해결법: 반드시 구조를 이해하는 `yq`를 사용하거나, 변수화를 통해 `.env` 파일만 수정하는 방식을 택하세요.
  • 실수: 이미지 태그와 컴포즈 버전이 서로 다르게 배포됨
    왜 발생하는가: 두 곳을 각각 따로 업데이트하는 스크립트를 짜서 한쪽이 실패했을 때 동기화가 깨지는 거예요.
    → ✅ 해결법: 버전 정보를 하나의 변수에 저장하고, 이를 모든 파일에 동시에 주입하는 통합 스크립트를 사용하세요.
  • 실수: 배포 후 이전 컨테이너가 죽지 않고 계속 실행됨
    왜 발생하는가: 태그를 `latest`로만 고정해서 사용하면, 파일 내용이 바뀌어도 도커가 새 이미지를 가져와야 한다는 것을 인지하지 못할 수 있어요.
    → ✅ 해결법: 항상 고유한 버전 태그를 사용하고, 배포 시 `docker compose pull`을 먼저 실행하는 단계를 포함하세요.
  • 실수: CI 서버의 권한 문제로 파일 수정이 안 됨
    왜 발생하는가: CI 실행 환경(Runner)의 작업 디렉토리에 쓰기 권한이 없기 때문이에요.
    → ✅ 해결법: 실행 권한(`chmod`)을 확인하거나, CI 도구가 파일을 직접 수정하기보다 빌드 단계에서 결과물을 생성하도록 설계하세요.
  • 실수: 자동화 스크립트 자체가 실패했는데 배포가 진행됨
    왜 발생하는가: 파이프라인 단계 간의 의존성 설정이 누락되었기 때문이에요.
    → ✅ 해결법: 각 단계가 성공해야만 다음 단계로 넘어가는 ‘fail-fast’ 설정을 반드시 확인하세요.
⚠️ 주의
자동화 스크립트를 처음 적용할 때는 반드시 실운영 서버가 아닌 스테이징(Staging) 환경에서 충분히 테스트를 거쳐야 해요. 스크립트 한 줄의 실수가 모든 컨테이너를 내려버릴 수 있습니다.

자주 묻는 질문

Q. 컴포즈 파일 버전을 바꾸면 모든 컨테이너가 재시작되나요?

네, 보통은 그래요. 이미지 태그나 환경 변수가 바뀌면 도커 컴포즈는 변경 사항을 감지하고 해당 컨테이너를 재생성해요. 서비스 중단을 최소화하려면 롤링 업데이트(Rolling Update) 전략을 함께 고민해야 해요.

Q. .env 파일을 사용하는 게 보안상 위험하지 않을까요?

`.env` 파일 자체에 비밀번호 같은 민감한 정보를 넣고 깃에 올리는 것은 매우 위험해요. 하지만 버전 번호 같은 설정값만 넣는 것은 괜찮아요. 민감한 정보는 CI/CD 도구의 ‘Secret’ 기능을 통해 주입하는 것이 정석이에요.

Q. yq를 꼭 써야 하나요? 그냥 텍스트로 해도 안 될까요?

작은 프로젝트라면 가능할 수도 있지만, 운영 환경에서는 권장하지 않아요. YAML은 구조가 곧 의미인데, 텍스트 수정은 그 의미를 파괴할 수 있거든요. 안전한 운영을 위해 `yq`를 사용하는 습관을 들이는 게 좋아요.

Q. 배포 중에 에러가 나면 어떻게 되나요?

잘 설계된 CI/CD 파이프라인이라면 에러 발생 시 즉시 중단되어야 해요. 이때 이전 버전의 이미지가 살아있는 상태에서 중단된다면 서비스는 유지되지만, 자동화 스크립트가 파일을 이미 덮어썼다면 롤백을 위한 이전 버전 파일을 따로 보관해 두는 전략이 필요해요.

Q. 버전 번호를 정하는 특별한 규칙이 있나요?

가장 대중적인 건 ‘Semantic Versioning’이에요. `Major.Minor.Patch` 구조로, 큰 변화(Major), 기능 추가(Minor), 버그 수정(Patch)을 구분해서 번호를 매기는 방식이죠. 이 규칙을 따르면 배포 이력을 관리하기가 훨씬 수월해요.

자동화로 완성하는 안정적인 컨테이너 운영

컴포즈 파일 버전 자동화는 단순한 편의 기능이 아니에요. 이는 사람이 실수할 수 있는 영역을 기계에게 맡기고, 개발자는 더 가치 있는 코드 작성에 집중하게 만드는 데브옵스(DevOps)의 핵심 실천이에요. 처음에는 스크립트를 짜고 도구를 설정하는 과정이 번거롭게 느껴질 수 있지만, 한 번 구축해 두면 배포의 공포에서 영원히 벗어날 수 있어요.

✅ 핵심 요약

  • 버전 정보의 원천(Source of Truth)을 Git Tag로 단일화하세요.
  • YAML 파일 수정 시에는 반드시 `yq` 같은 구조적 도구를 사용하세요.
  • `.env` 파일을 활용해 컴포즈 파일의 복잡도를 낮추세요.
  • 배포 전 `docker compose config`로 검증 단계를 반드시 거치세요.
  • 이미지 태그에 항상 고유한 버전을 사용하여 추적성을 확보하세요.
  • 실패 시를 대비해 이전 버전의 이미지와 설정 파일을 보관하세요.

오늘 바로 모든 것을 자동화하려고 욕심내지 마세요. 우선은 가장 자주 반복하는 명령어 하나, 예를 들어 버전 번호를 적는 일부터 스크립트로 옮겨 보는 건 어떨까요? 작은 자동화가 모여 거대한 안정성을 만듭니다.

🚀 다음 단계로 나아가기

  • 오늘 할 일: 현재 사용 중인 `docker-compose.yml`에서 버전 정보를 변수화하기
  • 이번 주 할 일: `yq`를 설치하고 로컬 환경에서 버전 치환 스크립트 테스트하기
  • 실행 직전 할 일: CI 도구(GitHub Actions 등)에 스크립트를 올리고 스테이징 서버에서 배포해 보기

더 깊이 있는 컨테이너 운영 기술이 궁금하다면, 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드를 참고해 보세요. 여러분의 배포 여정이 더 가벼워지기를 응원해요!

댓글 남기기