🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

CodeBuild로 빌드 자동화 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 20. · 5 Views

CodeBuild로 빌드 자동화 완벽 가이드

AWS CodeBuild를 활용한 빌드 자동화의 모든 것. buildspec.yml 작성부터 Docker 빌드, ECR 푸시까지 실무에 바로 적용 가능한 자동화 파이프라인을 구축합니다.


목차

  1. CodeBuild란?
  2. 빌드 프로젝트 생성
  3. buildspec.yml 작성
  4. Docker 빌드 설정
  5. ECR 푸시 자동화
  6. 빌드 로그 확인

1. CodeBuild란?

입사 6개월 차 김개발 씨는 매일 아침 출근하면 제일 먼저 하는 일이 있습니다. 코드를 받아서 빌드하고, 테스트를 돌리고, 문제가 없으면 배포 서버로 올리는 작업입니다.

어느 날 선배 박시니어 씨가 물었습니다. "매일 그 작업을 손으로 하고 있어요?

CodeBuild 사용해보는 게 어때요?"

CodeBuild는 AWS에서 제공하는 완전 관리형 빌드 서비스입니다. 마치 전문 요리사가 있는 주방처럼, 필요할 때마다 자동으로 빌드 환경을 만들고 코드를 컴파일한 뒤 정리까지 해줍니다.

직접 빌드 서버를 관리할 필요가 없고, 사용한 만큼만 비용을 지불하면 됩니다.

다음 코드를 살펴봅시다.

# buildspec.yml - CodeBuild 설정 파일의 기본 구조
version: 0.2

phases:
  pre_build:
    commands:
      # 빌드 전 준비 작업
      - echo "빌드 준비 중..."
      - aws --version
  build:
    commands:
      # 실제 빌드 작업
      - echo "빌드 시작"
      - npm install
      - npm run build
  post_build:
    commands:
      # 빌드 후 정리 작업
      - echo "빌드 완료"

김개발 씨는 매일 같은 작업을 반복하며 지쳐갔습니다. 코드를 풀 받고, 의존성을 설치하고, 빌드를 돌리고, 에러가 나면 다시 수정하고.

점심시간이 되어도 빌드가 끝나지 않으면 밥도 제대로 먹을 수 없었습니다. 박시니어 씨가 김개발 씨의 모니터를 보며 말했습니다.

"그 작업, 이제 그만 손으로 하세요. CodeBuild가 대신 해줄 수 있어요." CodeBuild란 정확히 무엇일까요?

쉽게 비유하자면, CodeBuild는 마치 24시간 대기하는 전문 요리사와 같습니다. 여러분이 레시피(코드)를 주면, 요리사는 자동으로 재료를 준비하고(환경 설정), 요리를 하고(빌드), 완성된 요리를 내어놓습니다(빌드 결과물).

요리가 끝나면 주방도 깔끔하게 정리해줍니다. 예전에는 어떻게 빌드를 했을까요?

개발팀은 사무실 한쪽에 빌드 전용 서버를 두었습니다. Jenkins 같은 도구를 설치하고, 서버가 죽지 않도록 24시간 관리해야 했습니다.

빌드가 몰리는 시간에는 서버가 느려져서 개발자들이 빌드 순서를 기다려야 했습니다. 더 큰 문제는 서버가 고장 나면 아무도 빌드를 할 수 없다는 점이었습니다.

김개발 씨도 지난주에 이런 일을 겪었습니다. 빌드 서버가 갑자기 다운되어 하루 종일 배포를 못 했던 적이 있었습니다.

시스템 관리자가 서버를 복구하느라 몇 시간을 허비했고, 그 사이 개발 일정은 밀려만 갔습니다. 바로 이런 문제를 해결하기 위해 CodeBuild가 등장했습니다.

CodeBuild를 사용하면 서버 관리가 필요 없습니다. AWS가 알아서 빌드 환경을 만들고, 빌드가 끝나면 환경을 정리합니다.

빌드가 10개든 100개든 동시에 처리할 수 있습니다. 무엇보다 사용한 시간만큼만 비용을 지불하면 됩니다.

또한 CodeBuild는 다양한 언어와 프레임워크를 지원합니다. Java, Python, Node.js, Go, Ruby 등 거의 모든 언어로 작성된 프로젝트를 빌드할 수 있습니다.

Docker도 지원하니 컨테이너 이미지도 자동으로 만들 수 있습니다. 위의 코드를 살펴보겠습니다.

buildspec.yml은 CodeBuild에게 "어떻게 빌드할지" 알려주는 설명서입니다. version: 0.2는 buildspec 파일의 버전을 의미합니다.

phases 섹션은 빌드 과정을 단계별로 나눈 것입니다. pre_build는 빌드 전 준비 단계, build는 실제 빌드 단계, post_build는 빌드 후 정리 단계입니다.

각 단계마다 commands에 실행할 명령어를 나열합니다. 마치 요리 레시피처럼 순서대로 작성하면 됩니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 온라인 쇼핑몰 서비스를 개발한다고 가정해봅시다.

개발자가 새로운 기능을 개발하고 GitHub에 코드를 푸시하면, CodeBuild가 자동으로 감지해서 빌드를 시작합니다. 빌드가 성공하면 테스트 서버에 자동으로 배포됩니다.

이 모든 과정이 사람의 개입 없이 몇 분 만에 완료됩니다. 많은 스타트업과 대기업에서 이런 자동화 파이프라인을 적극적으로 사용하고 있습니다.

개발자는 코드 작성에만 집중하고, 나머지 반복 작업은 자동화하는 것이 현대적인 개발 방식입니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 buildspec.yml 파일을 프로젝트 루트에 두지 않는 것입니다. CodeBuild는 기본적으로 프로젝트 최상위 폴더에서 buildspec.yml을 찾습니다.

다른 위치에 두면 빌드가 실패할 수 있습니다. 따라서 항상 프로젝트 루트에 파일을 배치해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다.

"이제 더 이상 빌드 때문에 스트레스받지 않아도 되겠네요!" CodeBuild를 제대로 이해하면 반복적인 빌드 작업에서 해방되고, 더 중요한 개발 업무에 집중할 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - buildspec.yml은 반드시 프로젝트 루트에 위치시키세요

  • 빌드 시간을 줄이려면 캐싱 기능을 활용하세요
  • 환경변수는 CodeBuild 콘솔에서 안전하게 관리할 수 있습니다

2. 빌드 프로젝트 생성

김개발 씨는 CodeBuild가 무엇인지 이해했지만, 어디서부터 시작해야 할지 막막했습니다. 박시니어 씨가 화면을 공유하며 말했습니다.

"먼저 빌드 프로젝트를 만들어야 해요. 한 번 같이 만들어 볼까요?"

빌드 프로젝트는 CodeBuild에서 빌드를 실행하는 기본 단위입니다. 마치 공장에 생산 라인을 설치하는 것처럼, 소스 코드 위치, 빌드 환경, 실행할 명령어 등을 설정합니다.

한 번 만들어두면 계속 재사용할 수 있어서 매우 편리합니다.

다음 코드를 살펴봅시다.

# AWS CLI로 CodeBuild 프로젝트 생성
aws codebuild create-project \
  --name my-build-project \
  --source type=GITHUB,location=https://github.com/myuser/myrepo.git \
  --artifacts type=NO_ARTIFACTS \
  --environment type=LINUX_CONTAINER,\
image=aws/codebuild/standard:5.0,\
computeType=BUILD_GENERAL1_SMALL \
  --service-role arn:aws:iam::123456789012:role/CodeBuildRole

# 프로젝트 생성 후 빌드 시작
aws codebuild start-build --project-name my-build-project

박시니어 씨는 AWS 콘솔을 열고 CodeBuild 서비스로 이동했습니다. 김개발 씨는 화면을 보며 따라 했습니다.

"생각보다 간단하네요?"라고 말하자, 박시니어 씨가 웃으며 답했습니다. "처음에만 설정하면 되니까요." 빌드 프로젝트 생성은 어떻게 진행될까요?

쉽게 비유하자면, 빌드 프로젝트는 마치 공장의 생산 라인 설계도와 같습니다. 어디서 원재료(소스 코드)를 가져올지, 어떤 기계(빌드 환경)를 사용할지, 어떤 순서로 작업할지(빌드 명령어)를 정의합니다.

한 번 설계도를 만들어두면 같은 방식으로 계속 생산할 수 있습니다. 빌드 프로젝트가 없다면 어떻게 될까요?

매번 빌드할 때마다 "어느 저장소에서 코드를 가져올까?", "어떤 환경에서 빌드할까?", "어떤 명령어를 실행할까?"를 다시 설정해야 합니다. 10번 빌드하려면 10번 설정을 반복해야 합니다.

이는 엄청난 시간 낭비입니다. 김개발 씨도 처음에는 매번 설정을 바꿔가며 빌드를 시도했습니다.

어떤 때는 Node.js 14 환경을 사용했다가, 다음 번에는 실수로 Node.js 12 환경을 선택했습니다. 당연히 빌드 결과가 달랐고, 왜 어제는 되던 게 오늘은 안 되는지 원인을 찾느라 몇 시간을 허비했습니다.

바로 이런 문제를 해결하기 위해 빌드 프로젝트를 미리 만들어둡니다. 빌드 프로젝트를 만들 때는 몇 가지 핵심 정보를 입력해야 합니다.

첫째, 소스 코드의 위치입니다. GitHub, GitLab, Bitbucket, 또는 AWS의 CodeCommit 등 다양한 저장소를 선택할 수 있습니다.

둘째, 빌드 환경입니다. 어떤 운영체제를 사용할지, 얼마나 강력한 컴퓨팅 성능이 필요한지 결정합니다.

셋째, **서비스 역할(Service Role)**입니다. 이것은 CodeBuild가 다른 AWS 서비스(예: S3, ECR)에 접근할 수 있도록 권한을 부여하는 것입니다.

마치 직원에게 사원증을 주는 것과 같습니다. 사원증이 있어야 회사 내 다른 부서에 출입할 수 있듯이, 서비스 역할이 있어야 CodeBuild가 필요한 리소스에 접근할 수 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. --name my-build-project는 프로젝트의 이름을 지정합니다.

나중에 이 이름으로 빌드를 실행하게 됩니다. --source는 소스 코드가 어디 있는지 알려줍니다.

여기서는 GitHub 저장소를 사용했습니다. --artifacts type=NO_ARTIFACTS는 빌드 결과물을 별도로 저장하지 않겠다는 의미입니다.

--environment는 빌드 환경을 정의합니다. type=LINUX_CONTAINER는 리눅스 컨테이너를 사용한다는 뜻이고, image=aws/codebuild/standard:5.0은 AWS가 제공하는 표준 이미지 버전 5.0을 사용한다는 의미입니다.

computeType=BUILD_GENERAL1_SMALL은 작은 컴퓨팅 성능을 사용하겠다는 설정입니다. 마지막으로 --service-role은 CodeBuild가 사용할 IAM 역할의 ARN을 지정합니다.

이 역할에는 필요한 권한이 미리 부여되어 있어야 합니다. 실제 현업에서는 어떻게 활용할까요?

한 핀테크 스타트업은 프론트엔드, 백엔드, 모바일 앱 등 여러 프로젝트를 운영합니다. 각 프로젝트마다 빌드 프로젝트를 하나씩 만들어두었습니다.

개발자가 코드를 푸시하면 해당 빌드 프로젝트가 자동으로 실행되어 빌드와 테스트를 진행합니다. 덕분에 팀원들은 빌드 설정을 신경 쓰지 않고 개발에만 집중할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 너무 강력한 컴퓨팅 타입을 선택하는 것입니다.

간단한 Node.js 프로젝트를 빌드하는데 BUILD_GENERAL1_LARGE 같은 큰 인스턴스를 사용하면 비용만 많이 나갑니다. 작은 프로젝트는 SMALL로 시작해서, 빌드 시간이 오래 걸리면 그때 크기를 늘리는 것이 좋습니다.

또 다른 실수는 서비스 역할에 필요한 권한을 제대로 부여하지 않는 것입니다. 예를 들어 ECR에 이미지를 푸시하려는데 ECR 접근 권한이 없으면 빌드가 실패합니다.

권한 설정은 빌드 프로젝트를 만들기 전에 미리 확인해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

박시니어 씨의 도움으로 첫 번째 빌드 프로젝트를 만든 김개발 씨는 뿌듯한 표정을 지었습니다. "이제 이 프로젝트로 계속 빌드하면 되는 거죠?" 빌드 프로젝트를 제대로 만들어두면 일관된 빌드 환경을 유지할 수 있고, 실수를 줄일 수 있습니다.

여러분도 프로젝트마다 빌드 프로젝트를 만들어두고 재사용하세요.

실전 팁

💡 - 작은 컴퓨팅 타입으로 시작해서 필요시 확장하세요

  • 서비스 역할에는 필요한 최소 권한만 부여하세요
  • 프로젝트 이름은 알아보기 쉽게 명확하게 지으세요

3. buildspec.yml 작성

빌드 프로젝트를 만들긴 했지만, 아직 빌드가 무엇을 해야 할지 알려주지 않았습니다. 김개발 씨가 고개를 갸우뚱하자, 박시니어 씨가 말했습니다.

"이제 buildspec.yml 파일을 작성해야 해요. 이게 바로 빌드의 레시피예요."

buildspec.yml은 CodeBuild에게 빌드 과정을 단계별로 지시하는 설정 파일입니다. 마치 요리 레시피처럼 재료 준비, 조리 과정, 마무리까지 모든 단계를 순서대로 적어둡니다.

YAML 형식으로 작성하며, 각 단계마다 실행할 명령어를 정의합니다.

다음 코드를 살펴봅시다.

version: 0.2

env:
  variables:
    NODE_ENV: "production"
    APP_NAME: "my-app"

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - echo "의존성 설치 시작"
      - npm ci
  pre_build:
    commands:
      - echo "환경 변수 확인"
      - echo $NODE_ENV
      - npm run lint
  build:
    commands:
      - echo "프로덕션 빌드 시작"
      - npm run build
  post_build:
    commands:
      - echo "빌드 완료"
      - ls -la dist/

artifacts:
  files:
    - '**/*'
  base-directory: dist

김개발 씨는 프로젝트 루트에 buildspec.yml 파일을 만들었습니다. 처음에는 어떻게 작성해야 할지 막막했지만, 박시니어 씨가 보여준 예제를 보니 생각보다 간단했습니다.

"이거 그냥 쉘 스크립트랑 비슷한 것 같은데요?" 맞습니다. buildspec.yml은 본질적으로 쉘 스크립트와 유사합니다.

쉽게 비유하자면, buildspec.yml은 마치 요리 레시피와 같습니다. 요리책에는 "1.

재료를 준비하세요", "2. 팬에 기름을 두르세요", "3.

재료를 볶으세요"처럼 순서대로 적혀 있습니다. buildspec.yml도 마찬가지로 "1.

의존성을 설치하세요", "2. 린트를 실행하세요", "3.

빌드를 시작하세요"라고 단계별로 지시합니다. buildspec.yml이 없던 시절에는 어떻게 했을까요?

개발자들은 빌드 서버에 직접 접속해서 명령어를 하나씩 입력했습니다. 실수로 순서를 바꾸거나 명령어를 빠뜨리면 빌드가 실패했습니다.

더 큰 문제는 각 개발자마다 조금씩 다른 방식으로 빌드를 하다 보니, 빌드 결과가 일관되지 않았다는 점입니다. 김개발 씨도 얼마 전까지는 메모장에 빌드 명령어를 적어두고, 빌드할 때마다 복사해서 붙여넣기를 했습니다.

어느 날은 실수로 npm install 대신 npm i를 입력했고, 다음 날은 npm ci를 입력했습니다. 당연히 결과가 달랐고, 원인을 찾느라 시간을 낭비했습니다.

바로 이런 문제를 해결하기 위해 buildspec.yml을 사용합니다. buildspec.yml 파일은 크게 몇 가지 섹션으로 구성됩니다.

첫째, version은 buildspec 파일의 버전을 명시합니다. 현재는 0.2를 사용합니다.

둘째, env 섹션에서는 빌드 중에 사용할 환경 변수를 정의합니다. 이렇게 하면 빌드 스크립트에서 환경 변수를 쉽게 참조할 수 있습니다.

셋째, phases 섹션이 가장 중요합니다. 여기서 빌드 과정을 단계별로 나눕니다.

install 단계에서는 런타임 버전을 지정하고 의존성을 설치합니다. pre_build 단계에서는 빌드 전에 실행할 작업(예: 린트, 테스트)을 정의합니다.

build 단계에서는 실제 빌드 명령어를 실행합니다. post_build 단계에서는 빌드 후 정리 작업을 수행합니다.

마지막으로 artifacts 섹션에서는 빌드 결과물을 어떻게 처리할지 정의합니다. files에는 어떤 파일을 결과물로 저장할지 지정하고, base-directory에는 결과물이 위치한 디렉토리를 명시합니다.

위의 코드를 자세히 살펴보겠습니다. runtime-versions에서 nodejs: 18을 지정하면 Node.js 18 버전을 사용합니다.

이렇게 하면 로컬 개발 환경과 빌드 환경의 Node.js 버전을 일치시킬 수 있습니다. npm cinpm install보다 빠르고 안정적인 의존성 설치 방법입니다.

CI 환경에서는 항상 npm ci를 사용하는 것이 권장됩니다. pre_build 단계에서 npm run lint를 실행하면 코드 품질을 자동으로 검사합니다.

만약 린트 오류가 있으면 빌드가 실패하므로, 품질이 낮은 코드가 배포되는 것을 방지할 수 있습니다. artifacts 섹션의 '**/*'는 모든 파일을 의미합니다.

base-directory: dist는 dist 폴더 안의 모든 파일을 결과물로 저장한다는 뜻입니다. 실제 현업에서는 어떻게 활용할까요?

한 이커머스 회사는 프론트엔드 프로젝트의 buildspec.yml에 보안 스캔 도구를 추가했습니다. 빌드할 때마다 자동으로 의존성 취약점을 검사하고, 문제가 발견되면 빌드를 중단합니다.

덕분에 보안 이슈가 있는 코드가 프로덕션에 배포되는 것을 사전에 차단할 수 있습니다. 또 다른 회사는 post_build 단계에서 빌드된 파일의 크기를 측정합니다.

파일 크기가 일정 기준을 넘으면 경고를 보내서, 불필요하게 큰 번들이 배포되지 않도록 관리합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수는 YAML 문법 오류입니다. YAML은 들여쓰기에 민감합니다.

스페이스 2칸으로 들여쓰기를 해야 하는데, 탭을 사용하거나 스페이스 개수를 틀리게 하면 파일이 제대로 파싱되지 않습니다. 빌드가 실패하면 먼저 YAML 문법을 검증해보세요.

또 다른 실수는 명령어 실행 순서를 잘못 정하는 것입니다. 예를 들어 npm run buildnpm ci보다 먼저 실행하면 의존성이 설치되지 않은 상태에서 빌드가 시작되어 실패합니다.

명령어 순서를 논리적으로 배치해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

buildspec.yml 파일을 작성한 김개발 씨는 파일을 저장하고 Git에 커밋했습니다. "이제 이 레시피대로 빌드가 자동으로 진행되겠네요!" buildspec.yml을 제대로 작성하면 일관되고 재현 가능한 빌드를 만들 수 있습니다.

여러분도 프로젝트에 맞는 buildspec.yml을 작성해보세요.

실전 팁

💡 - YAML 문법 오류를 방지하려면 온라인 YAML 검증 도구를 사용하세요

  • 민감한 정보는 환경 변수로 관리하고, 절대 하드코딩하지 마세요
  • 각 단계마다 echo로 로그를 남기면 디버깅이 쉬워집니다

4. Docker 빌드 설정

김개발 씨의 프로젝트는 Docker 컨테이너로 배포됩니다. buildspec.yml을 작성했지만, Docker 이미지를 어떻게 빌드해야 할지 고민이 되었습니다.

박시니어 씨가 말했습니다. "CodeBuild는 Docker 빌드도 지원해요.

Dockerfile만 있으면 됩니다."

CodeBuild는 Docker 이미지 빌드를 네이티브로 지원합니다. buildspec.yml에 Docker 명령어를 추가하면 자동으로 이미지를 빌드할 수 있습니다.

별도의 Docker 데몬 설정 없이도 빌드 환경에서 바로 Docker 명령어를 사용할 수 있어서 매우 편리합니다.

다음 코드를 살펴봅시다.

version: 0.2

phases:
  pre_build:
    commands:
      # Docker 로그인 (ECR 사용 시)
      - echo "Docker 빌드 환경 준비 중..."
      - aws --version
      - docker --version
  build:
    commands:
      # Docker 이미지 빌드
      - echo "Docker 이미지 빌드 시작"
      - docker build -t my-app:latest .
      - docker tag my-app:latest my-app:$CODEBUILD_BUILD_NUMBER
  post_build:
    commands:
      # 빌드 완료 확인
      - echo "Docker 이미지 빌드 완료"
      - docker images

김개발 씨는 처음에는 Docker 빌드를 위해 별도의 서버가 필요하다고 생각했습니다. 하지만 박시니어 씨의 설명을 듣고 깜짝 놀랐습니다.

"CodeBuild 안에서 바로 Docker를 사용할 수 있다고요?" 맞습니다. CodeBuild는 Docker in Docker 방식을 지원합니다.

쉽게 비유하자면, CodeBuild는 마치 다기능 작업실과 같습니다. 목공 작업도 할 수 있고, 금속 가공도 할 수 있고, 도장 작업도 할 수 있는 공간입니다.

마찬가지로 CodeBuild에서는 일반 빌드도 할 수 있고, Docker 이미지 빌드도 할 수 있습니다. 별도의 도구를 설치할 필요 없이 기본 제공되는 기능을 사용하면 됩니다.

예전에는 Docker 이미지를 어떻게 빌드했을까요? 개발자들은 로컬 컴퓨터에서 docker build 명령어를 실행했습니다.

빌드가 끝나면 Docker Hub나 ECR에 수동으로 푸시했습니다. 문제는 개발자마다 Docker 버전이 다르고, 로컬 환경이 달라서 빌드 결과가 일관되지 않았다는 점입니다.

김개발 씨도 이런 경험이 있습니다. 자신의 맥북에서는 잘 빌드되던 이미지가, 동료의 윈도우 컴퓨터에서는 빌드가 실패했습니다.

운영체제 차이 때문에 파일 권한이 달라졌고, 결국 며칠간 디버깅을 해야 했습니다. 바로 이런 문제를 해결하기 위해 CodeBuild에서 Docker 빌드를 합니다.

CodeBuild 환경은 모든 개발자에게 동일합니다. 같은 Docker 버전을 사용하고, 같은 리눅스 환경에서 실행됩니다.

따라서 누가 빌드를 트리거하든 결과는 항상 같습니다. 이것을 **재현 가능한 빌드(Reproducible Build)**라고 합니다.

Docker 빌드를 설정할 때는 몇 가지 중요한 점이 있습니다. 첫째, 빌드 환경에서 Docker가 활성화되어 있어야 합니다.

CodeBuild 프로젝트를 만들 때 privileged 모드를 활성화하면 Docker 명령어를 사용할 수 있습니다. 둘째, 이미지 태그를 체계적으로 관리해야 합니다.

위의 예제에서는 latest 태그와 함께 빌드 번호를 태그로 추가했습니다. $CODEBUILD_BUILD_NUMBER는 CodeBuild가 자동으로 제공하는 환경 변수로, 빌드마다 증가하는 고유 번호입니다.

위의 코드를 자세히 살펴보겠습니다. pre_build 단계에서 aws --versiondocker --version을 실행하는 이유는 환경이 제대로 설정되었는지 확인하기 위함입니다.

빌드 로그에 버전 정보가 출력되므로, 문제가 생겼을 때 어떤 환경에서 실행되었는지 알 수 있습니다. build 단계에서 docker build -t my-app:latest .는 현재 디렉토리의 Dockerfile을 사용해 이미지를 빌드합니다.

-t 옵션은 태그를 지정하는 것입니다. 빌드가 완료되면 docker tag 명령어로 추가 태그를 붙입니다.

$CODEBUILD_BUILD_NUMBER를 사용하면 각 빌드마다 고유한 태그를 가진 이미지가 생성됩니다. 예를 들어 10번째 빌드라면 my-app:10이라는 태그가 만들어집니다.

이렇게 하면 나중에 특정 버전의 이미지를 쉽게 찾을 수 있습니다. post_build 단계에서 docker images를 실행하면 빌드된 이미지 목록이 로그에 출력됩니다.

이미지가 제대로 생성되었는지 바로 확인할 수 있어서 디버깅에 유용합니다. 실제 현업에서는 어떻게 활용할까요?

한 SaaS 스타트업은 마이크로서비스 아키텍처를 사용합니다. 각 서비스마다 Dockerfile이 있고, CodeBuild로 자동으로 이미지를 빌드합니다.

개발자가 코드를 푸시하면 CodeBuild가 해당 서비스의 이미지를 빌드하고, ECR에 푸시한 뒤, Kubernetes 클러스터에 자동으로 배포합니다. 전체 과정이 10분 이내에 완료됩니다.

또 다른 기업은 멀티 스테이지 빌드를 사용합니다. Dockerfile에서 빌드 단계와 런타임 단계를 분리하여, 최종 이미지 크기를 최소화합니다.

CodeBuild는 이런 복잡한 Dockerfile도 문제없이 빌드합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수는 privileged 모드를 활성화하지 않는 것입니다. CodeBuild에서 Docker 명령어를 사용하려면 프로젝트 설정에서 "Privileged" 옵션을 체크해야 합니다.

이 옵션이 꺼져 있으면 docker build 명령어가 실패합니다. 또 다른 실수는 이미지 크기를 신경 쓰지 않는 것입니다.

불필요한 파일이 포함된 이미지는 용량이 커져서 푸시와 풀이 오래 걸립니다. .dockerignore 파일을 작성해서 불필요한 파일을 제외하세요.

다시 김개발 씨의 이야기로 돌아가 봅시다. 첫 Docker 빌드를 성공한 김개발 씨는 신이 났습니다.

"이제 이미지를 ECR에 올리기만 하면 되겠네요!" CodeBuild에서 Docker 빌드를 자동화하면 일관된 환경에서 안정적으로 이미지를 생성할 수 있습니다. 여러분도 Dockerfile과 buildspec.yml을 결합해서 완전 자동화된 이미지 빌드 파이프라인을 만들어보세요.

실전 팁

💡 - privileged 모드를 반드시 활성화하세요

  • 이미지 태그는 빌드 번호나 Git 커밋 해시를 사용하면 추적이 쉽습니다
  • .dockerignore로 불필요한 파일을 제외해 이미지 크기를 줄이세요

5. ECR 푸시 자동화

Docker 이미지를 빌드하긴 했지만, 이제 어디에 저장해야 할까요? 김개발 씨는 Docker Hub를 생각했지만, 박시니어 씨가 다른 제안을 했습니다.

"AWS를 사용한다면 ECR이 더 나아요. CodeBuild에서 자동으로 푸시할 수 있거든요."

**Amazon ECR(Elastic Container Registry)**은 AWS의 프라이빗 Docker 레지스트리입니다. CodeBuild에서 빌드한 이미지를 ECR에 자동으로 푸시하도록 설정하면, 별도의 인증 과정 없이 안전하게 이미지를 저장할 수 있습니다.

IAM 역할만 제대로 설정하면 모든 것이 자동으로 처리됩니다.

다음 코드를 살펴봅시다.

version: 0.2

phases:
  pre_build:
    commands:
      # ECR 로그인
      - echo "ECR 로그인 중..."
      - aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
      - REPOSITORY_URI=123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app
      - IMAGE_TAG=${CODEBUILD_BUILD_NUMBER:-latest}
  build:
    commands:
      # Docker 이미지 빌드
      - echo "이미지 빌드 중..."
      - docker build -t $REPOSITORY_URI:$IMAGE_TAG .
      - docker tag $REPOSITORY_URI:$IMAGE_TAG $REPOSITORY_URI:latest
  post_build:
    commands:
      # ECR에 푸시
      - echo "ECR에 이미지 푸시 중..."
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - docker push $REPOSITORY_URI:latest
      - echo "푸시 완료"

김개발 씨는 Docker Hub에 이미지를 올려본 적이 있었습니다. 매번 docker login으로 로그인하고, 수동으로 푸시해야 했습니다.

더 큰 문제는 Docker Hub의 무료 플랜은 프라이빗 저장소가 제한적이라는 점이었습니다. 박시니어 씨가 ECR을 추천한 이유가 있었습니다.

"ECR은 AWS 서비스들과 완벽하게 통합돼요. 보안도 훨씬 강력하고요." ECR 푸시 자동화란 무엇일까요?

쉽게 비유하자면, ECR은 마치 안전한 창고와 같습니다. 일반 창고(Docker Hub)는 누구나 접근할 수 있지만, 프라이빗 창고(ECR)는 권한이 있는 사람만 들어갈 수 있습니다.

CodeBuild는 회사 직원처럼 자동으로 권한을 받아서 창고에 물건(이미지)을 보관합니다. 예전에는 이미지를 어떻게 관리했을까요?

개발자들은 빌드가 끝나면 터미널을 열고 수동으로 명령어를 입력했습니다. docker login으로 로그인하고, docker push로 이미지를 푸시했습니다.

문제는 이 과정에서 실수가 자주 발생했다는 점입니다. 잘못된 태그를 푸시하거나, 로그인을 깜빡하고 푸시를 시도해서 실패하는 일이 빈번했습니다.

김개발 씨도 비슷한 경험이 있습니다. 어느 날 급하게 핫픽스를 배포하려는데, Docker Hub 로그인 비밀번호가 생각나지 않았습니다.

비밀번호를 리셋하고 다시 로그인하는 동안 30분이 흘렀고, 그 사이 서비스는 계속 오류 상태였습니다. 바로 이런 문제를 해결하기 위해 ECR 푸시를 자동화합니다.

ECR 푸시 자동화를 설정하려면 몇 가지 준비가 필요합니다. 첫째, ECR 저장소를 미리 생성해야 합니다.

AWS 콘솔이나 CLI로 저장소를 만들 수 있습니다. 저장소 이름은 프로젝트 이름과 같게 하면 관리하기 쉽습니다.

둘째, CodeBuild의 서비스 역할에 ECR 권한을 부여해야 합니다. ecr:GetAuthorizationToken, ecr:BatchCheckLayerAvailability, ecr:PutImage, ecr:InitiateLayerUpload 같은 권한이 필요합니다.

이 권한이 없으면 CodeBuild가 ECR에 접근할 수 없습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

aws ecr get-login-password 명령어는 ECR 로그인용 임시 비밀번호를 받아옵니다. 이 비밀번호는 12시간 동안 유효합니다.

파이프(|)로 docker login에 전달하면 자동으로 로그인이 됩니다. --password-stdin 옵션은 비밀번호를 표준 입력으로 받겠다는 의미입니다.

REPOSITORY_URI는 ECR 저장소의 전체 주소입니다. 형식은 계정ID.dkr.ecr.리전.amazonaws.com/저장소이름입니다.

IMAGE_TAG는 빌드 번호를 사용하며, 빌드 번호가 없으면 latest를 사용합니다. docker build 명령어에서 -t $REPOSITORY_URI:$IMAGE_TAG를 사용하면 이미지를 빌드하면서 동시에 태그를 지정합니다.

추가로 latest 태그도 붙여서, 항상 최신 이미지를 쉽게 찾을 수 있게 합니다. post_build 단계에서 docker push를 두 번 실행합니다.

한 번은 빌드 번호 태그를 푸시하고, 한 번은 latest 태그를 푸시합니다. 이렇게 하면 특정 버전과 최신 버전을 모두 ECR에 보관할 수 있습니다.

실제 현업에서는 어떻게 활용할까요? 한 핀테크 기업은 CodeBuild와 ECR을 연동해서 완전 자동화된 배포 파이프라인을 구축했습니다.

개발자가 main 브랜치에 코드를 머지하면, CodeBuild가 자동으로 이미지를 빌드하고 ECR에 푸시합니다. 그 다음 CodePipeline이 ECR의 새 이미지를 감지하고, ECS 클러스터에 자동으로 배포합니다.

전체 과정이 사람의 개입 없이 진행됩니다. 또 다른 기업은 이미지 스캔 기능을 활용합니다.

ECR에 이미지가 푸시되면 자동으로 보안 취약점 스캔이 실행됩니다. 취약점이 발견되면 Slack으로 알림을 보내서, 문제를 즉시 파악하고 조치할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 ECR 저장소를 미리 만들지 않는 것입니다.

CodeBuild가 이미지를 푸시하려는데 저장소가 없으면 푸시가 실패합니다. 저장소는 빌드 프로젝트를 설정하기 전에 미리 생성해두세요.

또 다른 실수는 리전을 잘못 지정하는 것입니다. ECR 저장소와 CodeBuild 프로젝트가 다른 리전에 있으면 접근이 안 될 수 있습니다.

같은 리전에 두는 것이 좋습니다. 마지막으로 IAM 권한 부족도 흔한 문제입니다.

CodeBuild 서비스 역할에 ECR 관련 권한이 제대로 부여되었는지 반드시 확인하세요. 다시 김개발 씨의 이야기로 돌아가 봅시다.

첫 ECR 푸시가 성공하자 김개발 씨는 환호성을 질렀습니다. "이제 이미지가 자동으로 ECR에 올라가네요!

정말 편하네요!" ECR 푸시를 자동화하면 수동 작업에서 해방되고, 실수 없이 안정적으로 이미지를 관리할 수 있습니다. 여러분도 CodeBuild와 ECR을 연동해서 자동화 파이프라인을 구축해보세요.

실전 팁

💡 - ECR 저장소는 빌드 전에 미리 생성하세요

  • 같은 리전에 CodeBuild와 ECR을 두면 네트워크 비용이 절감됩니다
  • 이미지 라이프사이클 정책을 설정해서 오래된 이미지는 자동 삭제하세요

6. 빌드 로그 확인

김개발 씨는 자동화를 모두 설정했지만, 빌드가 실패했을 때 어떻게 디버깅해야 할지 궁금했습니다. 박시니어 씨가 말했습니다.

"빌드 로그를 보면 무엇이 잘못되었는지 바로 알 수 있어요. CodeBuild는 모든 출력을 상세하게 기록하거든요."

CodeBuild는 빌드 과정의 모든 출력을 로그로 기록합니다. CloudWatch Logs에 자동으로 전송되며, 콘솔에서 실시간으로 확인할 수 있습니다.

빌드가 실패하면 로그를 보고 어느 단계에서 어떤 오류가 발생했는지 정확히 파악할 수 있습니다.

다음 코드를 살펴봅시다.

# buildspec.yml에 로그 개선 추가
version: 0.2

phases:
  pre_build:
    commands:
      - echo "========== 빌드 시작 =========="
      - echo "빌드 번호: $CODEBUILD_BUILD_NUMBER"
      - echo "Git 커밋: $CODEBUILD_RESOLVED_SOURCE_VERSION"
      - echo "빌드 시작 시간: $(date)"
  build:
    commands:
      - echo "========== 메인 빌드 =========="
      - docker build -t my-app . || { echo "Docker 빌드 실패"; exit 1; }
  post_build:
    commands:
      - echo "========== 빌드 완료 =========="
      - echo "빌드 종료 시간: $(date)"
      - echo "빌드 결과: $CODEBUILD_BUILD_SUCCEEDING"

# AWS CLI로 로그 확인
# aws logs tail /aws/codebuild/my-build-project --follow

김개발 씨의 첫 빌드는 실패로 끝났습니다. 화면에는 붉은색으로 "Build Failed"라는 메시지만 보였습니다.

어디가 문제인지 알 수 없어서 당황했습니다. 박시니어 씨가 다가와 "Build logs" 탭을 클릭했습니다.

"여기를 보면 뭐가 잘못됐는지 다 나와요." 빌드 로그는 문제 해결의 핵심입니다. 쉽게 비유하자면, 빌드 로그는 마치 블랙박스와 같습니다.

자동차 사고가 나면 블랙박스 영상을 보고 정확히 무슨 일이 있었는지 확인합니다. 마찬가지로 빌드가 실패하면 로그를 보고 어느 시점에 무슨 명령어가 실행되었고, 어디서 오류가 발생했는지 추적할 수 있습니다.

빌드 로그가 없다면 어떻게 될까요? 개발자들은 빌드가 왜 실패했는지 알 수 없어서, 추측으로 여기저기 수정해봐야 합니다.

"아마 의존성 문제일 거야", "환경 변수 설정이 틀렸을 거야"라고 짐작만 할 뿐입니다. 열 번 시도해서 우연히 한 번 성공하면 다행이지만, 대부분은 몇 시간을 허비하게 됩니다.

김개발 씨도 예전에 이런 경험이 있었습니다. 로컬에서는 잘 되던 빌드가 CI 환경에서 계속 실패했습니다.

로그가 없어서 원인을 찾을 수 없었고, 결국 선배에게 도움을 요청했습니다. 선배는 빌드 로그를 보더니 5분 만에 문제를 찾아냈습니다.

Node.js 버전이 달라서 생긴 문제였습니다. 바로 이런 문제를 해결하기 위해 빌드 로그를 꼼꼼히 확인해야 합니다.

CodeBuild의 로그는 크게 두 곳에 저장됩니다. 첫째, CodeBuild 콘솔의 Build logs 탭입니다.

여기서 빌드 과정의 전체 출력을 실시간으로 볼 수 있습니다. 빌드가 진행되는 동안에도 로그가 계속 갱신됩니다.

둘째, CloudWatch Logs에 영구적으로 보관됩니다. CodeBuild 콘솔에서는 최근 빌드 로그만 보이지만, CloudWatch Logs에서는 모든 과거 빌드 로그를 검색할 수 있습니다.

특정 오류 메시지를 검색하거나, 여러 빌드의 로그를 비교할 때 유용합니다. 위의 코드를 자세히 살펴보겠습니다.

echo "========== 빌드 시작 ==========" 같은 구분선을 추가하면 로그를 읽기가 훨씬 쉬워집니다. 수백 줄의 로그 속에서 어느 단계가 시작되고 끝나는지 한눈에 알 수 있습니다.

$CODEBUILD_BUILD_NUMBER$CODEBUILD_RESOLVED_SOURCE_VERSION 같은 환경 변수를 로그에 출력하면, 나중에 "이 빌드가 어떤 커밋에서 실행되었지?"를 쉽게 확인할 수 있습니다. || { echo "Docker 빌드 실패"; exit 1; } 부분은 오류 처리입니다.

명령어가 실패하면 명확한 메시지를 출력하고 빌드를 중단합니다. 이렇게 하면 어느 명령어에서 실패했는지 바로 알 수 있습니다.

$CODEBUILD_BUILD_SUCCEEDING 변수는 빌드가 성공 중인지 실패 중인지를 나타냅니다. 값이 0이면 실패, 1이면 성공입니다.

post_build 단계에서 이 값을 출력하면 최종 결과를 확인할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

한 DevOps 팀은 빌드 로그를 자동으로 분석하는 스크립트를 만들었습니다. 특정 오류 메시지(예: "Out of memory")가 로그에 나타나면 자동으로 Slack에 알림을 보냅니다.

덕분에 개발자가 로그를 일일이 확인하지 않아도 중요한 오류를 즉시 인지할 수 있습니다. 또 다른 팀은 빌드 시간 추적을 합니다.

각 단계의 시작과 종료 시간을 로그에 기록해서, 어느 단계가 가장 오래 걸리는지 분석합니다. 병목 구간을 찾아내서 최적화하면 빌드 시간을 크게 단축할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 민감한 정보를 로그에 출력하는 것입니다.

비밀번호, API 키, 데이터베이스 연결 문자열 같은 정보가 로그에 남으면 보안 문제가 발생합니다. CloudWatch Logs는 기본적으로 팀원 모두가 볼 수 있으므로, 절대로 민감한 정보를 echo로 출력하지 마세요.

또 다른 실수는 로그를 너무 장황하게 만드는 것입니다. 모든 파일 목록을 출력하거나, 불필요한 디버그 메시지를 계속 출력하면 로그가 너무 길어져서 정작 중요한 정보를 찾기 어렵습니다.

핵심 정보만 간결하게 로그에 남기세요. 마지막으로 오류가 발생해도 로그를 확인하지 않는 것도 문제입니다.

"빌드가 실패했네, 다시 실행해볼까?"라고 무작정 재시도하면 같은 오류가 반복됩니다. 반드시 로그를 확인하고 원인을 파악한 뒤 수정하세요.

다시 김개발 씨의 이야기로 돌아가 봅시다. 로그를 확인한 김개발 씨는 문제를 금방 찾았습니다.

"아, npm ci를 실행할 때 package-lock.json이 없어서 실패했구나!" 파일을 추가하고 다시 빌드하자 성공했습니다. 빌드 로그를 제대로 활용하면 문제를 빠르게 진단하고 해결할 수 있습니다.

여러분도 빌드가 실패하면 먼저 로그를 꼼꼼히 읽어보세요.

실전 팁

💡 - 각 단계마다 구분선과 타임스탬프를 추가하세요

  • 민감한 정보는 절대 로그에 출력하지 마세요
  • CloudWatch Logs Insights로 여러 빌드 로그를 한 번에 분석할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AWS#CodeBuild#Docker#ECR#CI/CD

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

Helm 마이크로서비스 패키징 완벽 가이드

Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.

EFK 스택 로깅 완벽 가이드

마이크로서비스 환경에서 로그를 효과적으로 수집하고 분석하는 EFK 스택(Elasticsearch, Fluentd, Kibana)의 핵심 개념과 실전 활용법을 초급 개발자도 쉽게 이해할 수 있도록 정리한 가이드입니다.

Spring Boot 상품 서비스 구축 완벽 가이드

실무 RESTful API 설계부터 테스트, 배포까지 Spring Boot로 상품 서비스를 만드는 전 과정을 다룹니다. JPA 엔티티 설계, OpenAPI 문서화, Docker Compose 배포 전략을 초급 개발자도 쉽게 따라할 수 있도록 스토리텔링으로 풀어냅니다.

Docker로 컨테이너화 완벽 가이드

Spring Boot 애플리케이션을 Docker로 컨테이너화하는 방법을 초급 개발자도 쉽게 이해할 수 있도록 실무 중심으로 설명합니다. Dockerfile 작성부터 멀티스테이지 빌드, 이미지 최적화, Spring Boot의 Buildpacks까지 다룹니다.

보안 아키텍처 구성 완벽 가이드

프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.