Blacksmith Docker 캐시는 개발 사이클을 얼마나 줄였나 — 1,527개 작업과 실제 설정 변화

Blacksmith Docker 캐시는 개발 사이클을 얼마나 줄였나 — 1,527개 작업과 실제 설정 변화

고객 환경과 우리 환경에 같은 CI를 억지로 넣지는 않는다. 클라이언트는 GitLab이나 CodeCommit에서 시작해 CodePipeline → CodeBuild → ECR·ECS 또는 CodePipeline → CodeBuild → CodeDeploy·EC2로 이어지는 경우가 많다. 소스, IAM, 네트워크와 배포 이력이 AWS 안에서 닫히는 구성이 중요하기 때문이다.

801플래닛이 직접 만드는 애플리케이션은 출발점이 다르다. GitHub → GitHub Actions → Blacksmith → ECR·ECS를 쓴다. GitHub Actions가 워크플로를 조정하고 Blacksmith가 작업을 실행한다. AWS 배포 권한은 장기 액세스 키 대신 GitHub OIDC로 짧게 발급한다.1

이 글은 Blacksmith를 모든 환경의 표준으로 권하는 소개가 아니다. 실제 계정에서 무엇을 봤는지, 공개된 성능 주장에 어느 정도 근거가 있는지, CodeBuild나 직접 운영하는 BuildKit과 비교하면 선택이 어디서 갈리는지를 기록한다. 참고로 제공받은 Findy Tools 리뷰는 본문이 회원 전용이라 제목과 공개된 작성자 정보만 확인했고 정량 근거에는 쓰지 않았다.2

두 경로는 모두 AWS에 배포하지만 제어면은 다르다. 위쪽에서 CodePipeline은 GitLab 또는 CodeCommit의 변경을 받아 CodeBuild를 실행한다. 컨테이너 경로는 이미지를 ECR에 올리고 ECS가 가져가며 인스턴스 경로에서는 CodeDeploy가 릴리스를 EC2에 전달한다.

고객 환경의 GitLab 또는 CodeCommit에서 CodePipeline과 CodeBuild를 거쳐 ECR·ECS 또는 CodeDeploy·EC2로 배포하는 경로와, 801플래닛의 GitHub Actions·Blacksmith·Docker 캐시·GitHub OIDC·IAM·ECR·ECS 경로를 비교한 AWS 아키텍처 다이어그램.
고객 환경의 AWS 중심 제어면과 801플래닛의 GitHub·Blacksmith 제어면. 두 컨테이너 경로는 ECR·ECS에서 만난다.

아래쪽에서는 GitHub Actions가 워크플로를 조정하고 Blacksmith가 BuildKit 작업을 실행한다. Docker 레이어 캐시는 러너 가까이에서 재사용한다. GitHub OIDC로 수명이 짧은 IAM 역할을 인수해 이미지를 ECR에 올리고 ECS는 그 이미지를 가져온다. 오른쪽 막대는 같은 커밋 태그에서 확인한 ECR 압축 이미지 네 개의 크기다.

두 파이프라인은 출발점부터 다르다

구분클라이언트에서 자주 쓰는 구성801플래닛 애플리케이션
소스와 제어면GitLab·CodeCommit + CodePipelineGitHub + GitHub Actions
빌드 실행AWS CodeBuildBlacksmith 관리형 러너
이미지와 배포ECR → ECS 또는 CodeDeploy → EC2ECR → ECS
권한의 중심CodeBuild 서비스 역할, AWS IAMGitHub OIDC로 AWS 역할 인수
우선하는 경계VPC·AWS 계정 안의 통제와 감사GitHub 개발 흐름, 빠른 피드백, 러너 운영 제거

Blacksmith는 GitHub Actions를 대체하는 CI 제품이 아니다. GitHub의 워크플로와 액션 생태계는 그대로 두고 runs-on 대상만 Blacksmith의 러너로 바꾼다. 공식 빠른 시작 문서도 GitHub 조직 전용이며 개인 저장소에는 쓸 수 없다고 명시한다.3

runs-on: blacksmith-2vcpu-ubuntu-2404

바꿀 범위가 작아 도입이 가볍다. 반대로 GitLab이나 CodeCommit이 소스의 중심이면 이 장점부터 사라진다. 그런 환경에서 Blacksmith를 억지로 끼우기보다 CodeBuild나 기존 GitLab Runner를 유지하는 편이 구성과 감사 경로가 단순하다.

6개월 관측값은 무엇을 말하나

2026년 1월 23일부터 7월 23일까지 조직 전체를 선택한 Blacksmith CI Analytics 화면에는 1,527개 작업이 잡혔다. 작업 시간 p50은 255초, 곧 4분 15초였다. p90은 5분 40초, p95는 6분 46초, p99는 12분 45초, 최댓값은 27분 22초였다.

2026년 1월 23일부터 7월 23일까지 Blacksmith GitHub Actions Analytics 화면. 총 1,527개 작업, p50 255초, 실패율 13.75%와 작업 시간 분포가 표시돼 있다.
801플래닛 조직의 6개월 GitHub Actions 작업 분포. 저장소 필터를 적용하지 않은 전체 값이다.

이 화면만으로 Blacksmith가 이전보다 몇 배 빨라졌다고 판단할 수는 없다. 전환 전 같은 커밋을 GitHub 제공 러너에서 반복한 기준선이 없기 때문이다. 13.75% 실패율도 Blacksmith 장애율이 아니다. 테스트 실패, 애플리케이션 오류, 설정 실수와 의도적으로 실패시킨 작업이 섞인 조직 전체 지표다. 공급자 신뢰성보다 어느 저장소와 작업부터 고칠지 찾는 운영 지표로 봐야 한다.

같은 기간 Docker Analytics에는 1,487회 빌드, 9.28% 실패율, 평균 캐시 사용량 14.8GB가 기록됐다. 빌드 대부분은 1분 안쪽에 몰렸지만 긴 꼬리는 약 7분까지 이어졌다.

Blacksmith Docker Analytics 화면. 1,487회 빌드, 실패율 9.28%, 평균 캐시 사용량 14.8GB와 빌드 시간 분포가 표시돼 있다.
같은 조직의 Docker 빌드 분포. 평균 캐시 사용량은 비용과 적중률을 함께 볼 때 의미가 있다.

Blacksmith 대시보드에서는 작업 시간, 실패율, 캐시와 저장소별 비용을 한곳에서 나눠 본다.4 GitHub Actions 로그만 볼 때보다 p95·p99의 긴 작업과 캐시가 커진 저장소를 찾기 쉽다. 우리에게 관측성은 부가 화면이 아니라 러너를 관리형으로 선택한 이유 중 하나였다.

같은 캐시를 붙여도 결과가 두 갈래로 갈렸다

2026년 8월 10일 운영 이미지 워크플로에 Blacksmith 영속 빌더와 이미지별 cache_key를 반영했다. 외부 cache-from·cache-to는 없앴다. 빌드 결과는 push: true로 ECR에 바로 보냈다. Blacksmith가 빌더 디스크 전체를 보존하므로 Docker 레이어뿐 아니라 RUN --mount=type=cache로 만든 pnpm 저장소도 다음 실행에서 이어받는 구성이다.5

첫 전후 비교는 단순한 성공담이 아니었다.

API Docker 빌드 표본적용 전적용 후해석
전체 중앙값77초, n=998.5초, n=6콜드·무효화가 섞여 28% 느려짐
웜 표본77초52초, n=332.5% 단축
콜드·무효화 표본77초164초, n=3113% 증가

웹은 적용 후 첫 성공 표본이 161초짜리 콜드 빌드 한 건뿐이어서 이 시점에는 비교하지 않았다. API도 캐시가 이어진 실행만 빨랐다. 잠금 파일이나 Docker 입력이 바뀌면 의존성 레이어부터 다시 만들었다. 캐시가 비어 있는 첫 실행은 기존 중앙값보다 오래 걸렸다.

캐시 스냅샷 계보가 더 까다로웠다. 여러 실행이 영속 디스크 저장 성공을 기록했는데도 같은 이전 상위 스냅샷을 복원한 흔적이 있었다. 한 실행은 잠금 파일이 바뀌지 않았는데 의존성 설치를 다시 수행했고 빌더 설치에만 77.4초를 썼다. 다음 실행에서 새 스냅샷을 복원한 뒤에야 설치 레이어가 다시 CACHED가 됐다. Blacksmith는 같은 키에 동시에 기록할 때 최종 쓰기 우선(Last Write Wins)을 적용한다고 설명하지만 우리가 살핀 빌드끼리는 실행 시간이 겹치지 않았다. 오래된 스냅샷이 복원된 정확한 원인은 확정하지 않았다.5

cache_key를 실행 경계로 바꿨다

첫 설정은 동시성 그룹을 이미지 이름과 소스 SHA의 조합으로 만들었다. 소스가 다르면 같은 영속 디스크에 쓰는 작업도 동시에 실행될 수 있는 구조였다. 이를 아래처럼 cache_key 기준으로 바꿨다.

concurrency:
  group: build-seal-${{ inputs.cache_key }}
  cancel-in-progress: false

GitHub Actions는 같은 동시성 그룹에서 한 작업만 실행한다.6 이제 API·웹·Automation Orchestrator처럼 캐시 키가 다른 이미지는 계속 병렬로 빌드하지만 같은 영속 디스크를 갱신하는 기록 작업은 앞선 작업의 후처리 단계가 끝난 뒤 실행된다. 빌드·서명·ECR 다이제스트 계약은 건드리지 않았다. 관측된 오래된 스냅샷의 원인을 증명한 수정은 아니다. 같은 디스크에 기록하는 작업끼리의 경합을 막는 방어 설정에 가깝다.

2026년 8월 1일부터 12일까지 Castflow 저장소의 Blacksmith Sticky Disk 화면. API Docker build cache는 20.59GB, Web cache는 10.30GB이며 두 항목 모두 amd64로 표시돼 있다.
2026년 8월 12일의 저장소별 Sticky Disk. API 20.59GB와 웹 10.30GB를 서로 다른 캐시 키로 유지한다.

당시 두 캐시가 차지한 공간은 합계 30.89GB였다. 현재 공개 단가인 GB·월 0.50달러를 단순 적용하면 두 디스크가 한 달 내내 같은 크기로 유지될 때 약 15.45달러다. 실제 청구는 시간에 따른 사용량과 다른 저장소를 함께 계산하므로 이 값과 같지 않다. 캐시 용량이 곧 적중률을 뜻하지도 않는다. 이미지별 키는 서로 무관한 레이어가 같은 디스크에서 밀려나는 일을 줄이지만 잘못 나눈 키는 저장공간만 늘린다.

개발 사이클은 다섯 가지 설정을 함께 바꾸며 짧아졌다

기록 작업 직렬화를 main에 반영한 뒤 Docker 입력이 바뀐 실행과 그대로인 후속 웜 실행을 비교했다. Docker 단계와 전체 이미지 작업은 서로 다른 측정 단위이므로 나눠 기록했다.

측정 단위콜드·무효화 실행후속 웜 실행변화
API Docker 단계4분 26초4초98.5% 단축
API 전체 이미지 작업5분 7초38초87.6% 단축
웹 전체 이미지 작업4분 21초36초86.2% 단축
Blacksmith의 warm Web image job Metrics 화면. 전체 duration 36초, Build and push Web image 3초, peak memory 421MB, CPU p50 23%와 p99 56%, disk read 369MB와 write 262MB가 표시돼 있다.
웜 웹 이미지 작업의 실제 지표. 전체 36초 중 이미지 빌드·전송 단계는 3초였고, 최대 메모리는 421MB였다.

같은 화면에서 CPU는 p50 23%, p99 56%였고 디스크 I/O는 읽기 369MB, 쓰기 262MB였다. 이 실행에서는 CPU를 끝까지 쓰는 계산보다 준비된 캐시와 이미지 레이어 재사용이 시간을 좌우했다. 이후 두 번의 통제된 웜 빌드에서도 API Docker 단계 4초, 웹 Docker 단계 3초가 반복됐다. 로그 수집 결함을 고친 뒤 수행한 운영 배포 3회의 이미지 작업 중앙값도 API 37초, 웹 36초였다. 36초를 모든 빌드의 보장값으로 쓰지는 않지만 단일 표본에 머물렀던 근거는 반복 관측으로 보강됐다.

설정 1. 이미지 준비는 병렬로, 운영 배포는 순차로 실행했다

처음에는 API 이미지 준비와 배포가 끝난 뒤 웹 이미지를 만들었다. 서로 다른 cache_key를 쓰는 두 이미지가 같은 디스크를 두고 경쟁하지 않는데도 준비 단계까지 직렬로 묶여 있었다. 그래서 두 이미지 작업은 같은 검사 결과를 기다린 뒤 함께 시작하고, 실제 배포만 API에서 웹 순서로 유지했다.

build-api-image:
  needs: [checks, instagram-campaign-workflow-acceptance]

build-web-image:
  needs: [checks, instagram-campaign-workflow-acceptance]

deploy-api:
  needs: [build-api-image]

deploy-web:
  needs: [build-web-image, deploy-api]

이 의존 관계는 이미지 준비와 릴리스 순서를 분리한다. API·웹 이미지 작업은 1초 차이로 시작했지만 웹 배포는 API 마이그레이션과 배포가 성공한 뒤에만 열렸다. 이미지 준비 경과 시간은 3분 25초에서 2분 11초로 36% 줄었다. 검사 완료부터 전체 배포 완료까지는 12분 47초에서 11분 18초로 11.6%, 실질 전체 실행은 18분 27초에서 17분 45초로 3.8% 줄었다. Docker 작업을 겹친 효과는 분명했지만 전체 실행에서는 ECS 대기가 더 큰 비중을 차지했다.

설정 2. 단일 CI 관문을 네 작업과 집계 관문으로 나눴다

Docker만 빨라져도 코드 리뷰가 단일 CI 관문을 기다리면 개발 사이클은 짧아지지 않는다. 기존 테스트·빌드·린트를 계약 검사, DB 업그레이드, API 테스트, 빌드·린트 작업으로 나눠 같은 시각에 시작했다. 보호 규칙이 참조하던 Test, Build, and Lint라는 이름은 결과만 모으는 집계 관문으로 남겼다.

병렬 작업실제 소요 시간
CI Contracts and Infrastructure1분 13초
Build and Lint Packages1분 44초
API Tests1분 50초
DB Upgrade2분 36초

PR 검증 표본에서 임계 경로는 5분 50초에서 2분 54초로 50.3% 줄었다. 이 구성을 main에 병합한 운영 표본은 2분 18초에 검사를 마쳐 기존보다 3분 32초, 곧 60.6% 짧았다. PR 이벤트에서는 운영 이미지와 배포를 계속 건너뛰었다. 각 작업이 의존성 설치와 환경 설정을 반복해 첫 표본의 러너 총사용 시간은 약 28% 늘었다. 러너 사용량이 늘어도 리뷰 피드백을 앞당기는 쪽을 택했다.

설정 3. BuildKit 기록에서 캐시 실패 지점을 자동으로 읽었다

관측도 워크플로 안으로 옮겼다. BuildKit 기록에서 빌드 소요시간, 캐시된 단계 비율, 캐시되지 않은 첫 Dockerfile 단계를 읽어 작업 요약에 남긴다.7 직전 소스와 Docker 입력이 같고 이전 검증 완료 이미지가 있을 때만 웜 후보로 분류한다. 30초를 넘거나 캐시된 단계가 60% 미만이면 경고를 내되 배포는 막지 않는다.

main 실행에서 관측기는 API 46초·캐시 43%, 웹 61초·캐시 41%를 보고했다. 수동 로그에서 처음 캐시되지 않은 단계는 각각 COPY packages/database/COPY packages/shared-types/였다. 그런데 작업 요약에는 First uncached step: none이 찍혔다. 캐시가 정상이어서가 아니라 docker buildx history logs가 단계 로그를 표준 오류로 내보내는데 표준 출력만 파일에 저장한 파서 결함이었다.

docker buildx history logs "$build_id" --progress plain > "$log_file" 2>&1

2>&1은 표준 오류를 같은 로그 파일로 합친다. 이 한 줄 뒤 none은 실제로 캐시되지 않은 Dockerfile 단계가 없을 때만 나온다. 수정 후 Docker 입력을 건드리지 않는 변경을 세 번 순차 배포했고 결과는 아래처럼 재현됐다.

운영 실행API 이미지 작업웹 이미지 작업Dockerfile 캐시회귀 경고
3155966230245초45초API·웹 전 단계 적중없음
3156065202735초35초API·웹 전 단계 적중없음
3156152667437초36초API·웹 전 단계 적중없음

세 실행은 앞선 배포가 끝난 뒤 시작했고 모두 docker-inputs-unchanged로 분류됐다. 이미지별 캐시 키와 기록 작업 직렬화가 통제된 웜 조건에서 안정적으로 작동한다고 볼 근거가 생겼다. 초기의 오래된 스냅샷이 왜 복원됐는지까지 소급해 증명한 것은 아니다.

설정 4. 지연된 재사용 워크플로의 실행 경계를 보강했다

한 운영 실행에서는 API 배포 뒤 늦게 시작된 웹 재사용 작업이 부모 실행 상태의 전파 경합 때문에 Docker 단계에 들어가기 전에 차단됐다. 캐시 문제가 아니었다. 실행 경계 스크립트가 상태를 최대 4회, 2초 간격으로 다시 읽도록 바꾸고, 실행 중이거나 completed/success인 공식 작업만 허용했다. failure, cancelled, skipped는 계속 차단한다. 소스 SHA, 워크플로, 저장소, 실행자 같은 불변값이 다르면 재시도 없이 즉시 실패한다.

수정 뒤 API와 웹의 경계 검증은 각각 1초에 통과했고 Docker 빌드·전송은 5초와 4초였다. API 배포 5분 10초, 웹 배포 3분 28초까지 성공하면서 이전에 실패했던 API에서 웹 전환도 복구됐다. 성능 개선을 이유로 다이제스트 검증, 서명, API 선행 배포 같은 안전 계약을 느슨하게 만들지 않았다.

설정 5. Slack 알림을 배포 상태판으로 바꿨다

Slack 알림에는 환경, ECS 클러스터·서비스, 커밋과 불변 이미지 다이제스트, 태스크 정의 변경, 마이그레이션·전체·안정화 시간, 실행 중·대기 중 태스크 수를 넣었다. 실패하면 어느 단계에서 멈췄고 ECS나 마이그레이션이 어떤 이유를 돌려줬는지도 남긴다. 하나의 메시지를 시작, 이미지 준비, 성공 또는 실패 상태로 갱신한다. Slack 장애는 정상 배포를 실패시키지 않지만 API의 ok, 메시지 시각과 HTTP 오류는 검증해 GitHub 경고로 남긴다. API·웹 운영 실행에서 세 단계 전송은 모두 성공했으며 Slack 화면의 실제 표현을 별도로 열어 확인하지는 않았다.

프로젝트 전체에서 얻은 효과는 숫자 하나가 아니다. Docker 변경이 없는 이미지 작업은 수십 초로 안정됐고 CI 분할은 리뷰 대기를 3분 32초 줄였다. 그 결과 전체 배포의 주된 병목은 DB 마이그레이션과 ECS 안정화로 이동했다. 빌드 시간, CI 임계 경로, 러너 총사용 시간, 배포 안정화 시간을 따로 관리하게 된 것이 이번 개선의 더 큰 성과다.

조기 적용의 경제적 이익은 얼마였을까

이 수치를 회계상 이익으로 부를 수는 없다. 1,487회 Docker 빌드의 저장소별 웜 적격률도 없고 단축된 대기 시간이 실제 개발 시간으로 얼마나 돌아왔는지도 측정하지 않았기 때문이다. 대신 관측값과 가정을 분리한 반사실 시나리오로 경제적 가치를 계산했다.

무효화 실행과 최신 웜 중앙값을 비교하면 웹 이미지 작업은 225초, API 이미지 작업은 270초 짧아졌다. 평균 247.5초를 반올림한 247초를 웜 적격 빌드 한 건의 시간 절감값으로 놓았다. 1,487회 전체가 이만큼 빨라졌다고 가정하지 않았다. Docker 입력이 그대로여서 캐시를 재사용할 비율을 30%·50%·70%로 나눴다.

엔지니어가 CI 대기 전부를 생산 시간으로 바꾸지도 않는다. 대기 중 다른 업무를 처리하고 여러 빌드가 같은 PR에 묶이기도 한다. 그래서 줄어든 경과 시간 가운데 실제 집중 업무로 돌아오는 비율을 25%·40%·60%로 두었다. 완전부담 인건비는 시간당 7만원·10만원·15만원, 환율은 계산 편의를 위한 1달러당 1,400원 가정이다. 회사 급여나 실제 환전값이 아니다.

시나리오웜 적격률줄어드는 경과 시간유효 엔지니어 시간생산 여력의 가치추가 플랫폼 비용구현 인건비 전 경제효과
보수30%30.6시간7.7시간54만원12만원42만원
기준50%51.0시간20.4시간204만원11만원193만원
상향70%71.4시간42.9시간643만원11만원632만원

추가 플랫폼 비용은 현재 영속 디스크 30.89GB가 6개월 내내 같은 크기였다는 보수적 가정에서 출발한다. 월 15.45달러를 6개월 적용한 92.70달러에서 짧아진 러너 시간의 분당 0.004달러를 뺐다. 실제 캐시가 6개월 동안 점진적으로 커졌다면 저장 비용을 높게 잡은 계산이다. 환율 가정까지 적용한 순증 비용은 시나리오별 약 11만~12만원이다.58

1,487회는 조직 전체 Docker 빌드 수이고 30.89GB는 한 저장소의 API·웹 캐시 두 개를 관측한 값이다. 모든 저장소의 캐시 비용 구조가 같다고 가정하지 않았다. 다른 저장소에도 별도 영속 디스크가 필요하다면 전체 플랫폼 비용은 표보다 커진다. 반대로 관측한 캐시가 6개월에 걸쳐 점진적으로 커졌다면 표의 저장공간 비용은 실제보다 높다.

기준 시나리오의 구현 인건비 전 경제효과는 약 193만원이다. 대부분은 러너 청구 절감이 아니라 엔지니어가 되찾은 20.4시간에서 나온다. 러너 비용 절감은 12.24달러에 그친다. 이 구조에서는 분당 단가보다 피드백을 기다리며 잃는 집중 시간이 경제성을 좌우한다.

설정 변경, 검증과 운영 관측에 실제로 쓴 엔지니어 시간은 기록하지 않았다. 기준 시나리오의 시간가치인 시간당 10만원을 적용하면 구현과 6개월 유지 작업이 19.3시간보다 적을 때 손익이 양수다. 보수 시나리오의 손익분기점은 약 6.0시간이다. 25초 하한 모델에서는 구현 인건비 전 경제효과가 8만원뿐이어서 0.8시간만 투입해도 사라진다. 그래서 이 표는 생산 여력의 가치에서 플랫폼 비용을 뺀 값이지 프로젝트 회계의 최종 이익이 아니다.

247초가 대표값으로 너무 공격적일 가능성도 검토했다. 초기 API 웜 중앙값에서 직접 확인한 25초 단축만 적용하면 50% 적격률에서 경과 시간은 5.2시간, 유효 시간은 2.1시간으로 줄어든다. 같은 시간가치와 비용 가정의 구현 인건비 전 경제효과는 약 8만원이다. 작은 양수지만 측정 오차와 운영비를 더하면 쉽게 사라진다. 후속 3회 완전 적중은 247초 입력의 재현 근거를 강화했지만 실제 구현·검증 시간은 여전히 기록하지 않았다. 193만원은 실현 이익이 아니라 이미지 작업 개선이 반년 일찍 안정화됐을 때의 기준 추정치다.

CI 병렬화는 별도 경제 경로다. main 표본에서 PR 한 건의 임계 경로를 3분 32초, 곧 212초 줄였다. 같은 집중시간 환원율 40%와 시간당 10만원을 적용하면 영향받는 PR 수에 따른 가치는 아래와 같다.

영향받는 PR줄어드는 리뷰 대기유효 엔지니어 시간시간가치
50건2.9시간1.2시간약 12만원
100건5.9시간2.4시간약 24만원
200건11.8시간4.7시간약 47만원

PR 수와 Docker 빌드의 대응 관계가 없으므로 이 값은 193만원 표에 더하지 않았다. 같은 대기를 두 번 세거나 병렬화로 늘어난 러너 사용량을 빠뜨릴 수 있기 때문이다.

숫자로 잡지 않은 부수 효과도 있다. 실패를 몇 분 일찍 발견하면 개발자는 이전 문맥이 남아 있을 때 수정한다. 캐시 성능 회귀에서 캐시되지 않은 첫 단계를 바로 찾으면 플랫폼 엔지니어의 로그 탐색이 줄어든다. 실험 한 회의 비용이 낮아지면 같은 기간에 더 많은 변경을 검증한다. 잠재 효과지만 현재 자료로 금액을 정하지 않았다. 다음 2주 실험에서는 PR별 대기 시간, 재시도 횟수, 실패 뒤 다음 코드 전송까지의 시간을 함께 모아야 한다.

성능 주장의 근거를 세 층으로 나눠 봤다

“최대 40배 빠른 Docker 빌드”는 모든 빌드에 적용되는 보장이 아니다. Blacksmith 문서도 이를 고객이 보고한 2~40배 개선으로 표현한다.5 각 자료의 이해관계와 실험 조건을 표에 함께 적었다.

자료공개된 결과이 글의 해석
Blacksmith 캐시 엔지니어링 글114MB 캐시 다운로드가 49.8MB/s에서 327.5MB/s로 증가한 사례에서 약 6.6배. 러너와 캐시의 콜로케이션 효과를 보여 주지만 공급자 자체 측정이다.9
Agentgateway 사용기E2E 작업이 1011분에서 23분으로 감소약 3~5배. 독립 사용기지만 오픈소스 프로젝트가 Blacksmith 후원을 받았다고 밝힌 사례다.10
원격 BuildKit 직접 구성Go 서비스 6개가 약 2분에서 10~17초로 감소영속 캐시의 효과는 직접 구성으로도 재현됐다. 같은 실험의 큰 Node 이미지는 --load 전송 때문에 약 3분 느려졌다.11
801플래닛 계정작업 p50 4분 15초, Docker 빌드 1,487회조직 전체 운영 상태다. 앞 절의 저장소별 웜·콜드 비교와 달리 GitHub 제공 러너를 쓴 같은 커밋의 A/B 기준선은 없다.

공통 원리는 단순하다. 임시 러너가 끝날 때 BuildKit의 작업 공간까지 사라지면 RUN --mount=type=cache로 만든 의존성 캐시도 함께 사라진다. Blacksmith는 저장소별 Docker 레이어 캐시를 영속 저장공간에 두고 다음 러너에 붙인다. 직접 구성한다면 원격 buildkitd와 영속 볼륨, GC 정책, 동시성, 격리와 장애 복구를 직접 맡아야 한다.

병목이 캐시와 단일 코어 CPU에 있으면 효과가 크다. 큰 이미지를 러너로 다시 가져오는 --load, 외부 레지스트리 전송, 느린 통합 테스트가 대부분이면 러너만 바꿔도 큰 차이가 없거나 더 느려지기도 한다. 최대 몇 배라는 문구보다 같은 커밋의 p50·p95, 캐시 적중률, 성공한 작업 한 건의 비용을 비교하는 편이 정확하다.

ECR 이미지 크기도 러너 성능만큼 중요했다

실제 ECR에 올라간 네 최종 이미지는 압축 기준 79.9~330.5MB였고 최종 단계에 남긴 실행 파일과 운영 의존성이 크기 차이를 만들었다.

2026년 7월 23일 서울 리전의 사내 ECR 저장소 네 곳을 읽기 전용으로 조회했다. 같은 커밋 태그를 기준으로 DescribeImages.imageSizeInBytes와 OCI 매니페스트의 레이어 목록을 확인했다. 계정 ID와 저장소명은 공개하지 않았다. ECR 수치는 압축되어 저장된 이미지 크기다. 로컬 docker images가 표시하는 압축 해제 크기나 컨테이너가 쓰는 디스크 용량과 같지 않다.12

최종 이미지 역할최종 단계에 남긴 주요 항목ECR 압축 크기레이어 수최대 압축 레이어
Next.js standalone·public·static81.3MB1041.4MB
API운영 의존성·NestJS dist·Prisma245.2MB17114.6MB
단일 JS 실행체Node.js 실행 환경·dist/main.js79.9MB749.9MB
Automation Orchestrator운영 의존성·Temporal·데이터베이스 워크스페이스 산출물330.5MB20192.3MB

네 Dockerfile은 모두 다단계 빌드를 쓴다. 잠금 파일과 각 워크스페이스의 package.json을 소스보다 먼저 복사한 뒤 pnpm install을 실행한다. 애플리케이션 코드만 바뀌면 의존성 설치 레이어를 재사용할 수 있는 순서다. .dockerignorenode_modules, 기존 dist.next, 인프라 코드, 문서와 .github를 빌드 컨텍스트에서 뺀다. Docker도 변경 빈도가 낮고 비용이 큰 단계를 앞에 두고 빌드 컨텍스트를 작게 유지하도록 권한다.13

최종 크기는 최종 단계 구성에 따라 갈렸다. 웹은 Next.js standalone 결과와 정적 파일만 복사해 81.3MB였다. API는 운영 의존성과 빌드 산출물, Prisma 관련 파일을 포함해 245.2MB였다. 단일 JS 실행 이미지는 Node.js 실행 환경과 dist/main.js만 담아 79.9MB였다. 오케스트레이터는 Temporal·데이터베이스 워크스페이스의 운영 의존성과 산출물을 함께 담아 330.5MB였다. 빌더 단계의 도구를 최종 이미지에서 제외하는 다단계 빌드의 이점은 같아도, 실행 환경에 무엇을 남기느냐에 따라 결과는 4배 넘게 벌어졌다.14

현재 워크플로는 docker/build-push-action에서 push: true로 ECR에 바로 보낸다. 큰 이미지를 러너의 로컬 Docker 데몬으로 되가져오는 --load 경로는 쓰지 않는다. 그래도 운영 의존성이 바뀌어 100MB가 넘는 레이어가 무효화되면 다시 빌드하고 전송해야 한다. Blacksmith가 캐시를 가까이 둬도 애플리케이션의 레이어 경계나 큰 실행 이미지까지 고쳐 주지는 않는다.

우리는 러너 시간만으로 실험을 평가하지 않는다. 같은 커밋의 콜드·웜 빌드 시간과 함께 ECR 압축 크기, 가장 큰 변경 레이어, 이미지 전송 시간, ECS에서 새 태스크가 준비될 때까지 걸린 시간을 기록해야 한다. 캐시가 빠른지와 배포할 이미지가 가벼운지는 별개의 질문이다.

단가 계산과 실제 청구는 다르다

2026년 7월 23일 공개 가격에서 GitHub 제공 Linux 2코어 러너는 분당 0.006달러, Blacksmith Ubuntu x64 2 vCPU는 0.004달러다.158 AWS CodeBuild 가격 페이지의 general1.small 예시는 분당 0.005달러를 쓴다.16

무료 분, GitHub 요금제, 캐시와 로그 비용을 빼고 같은 10,000분이 청구됐다고 가정한 컴퓨트 비용은 아래와 같다.

실행 계층공개 단가10,000분 컴퓨트 비용별도 고려
GitHub 제공 Linux 2코어$0.006/분$60요금제별 포함 분, GitHub Actions 캐시·아티팩트 저장
Blacksmith Ubuntu x64 2 vCPU$0.004/분$40Docker 레이어 캐시 $0.50/GB·월, 고정 IP $100/IP·월
CodeBuild general1.small 예시$0.005/분$50100분 무료, CloudWatch Logs·S3·KMS·CodePipeline 등

이 표는 단가를 분리해서 보는 계산일 뿐 TCO 순위가 아니다. CPU 세대와 메모리, 분 단위 반올림, 실제 실행 시간, 네트워크와 캐시 방식이 서로 다르다. CodeBuild는 공유 레이어 캐시를 쓰는 Docker 이미지 서버도 제공하며 실행 중 서버와 대기 캐시에 별도 과금한다.16 Blacksmith에서 관측한 평균 캐시 14.8GB를 현재 단가로 단순 환산하면 월 7.40달러다.

실제 청구서는 더 작았다. 2026년 3월부터 7월까지 다섯 번의 청구는 각각 4.31달러, 6.26달러, 22.13달러, 4.65달러, 9.97달러였다. 합계는 47.32달러, 월평균은 9.46달러다.

2026년 3월부터 7월까지 Blacksmith 청구 내역. 4.31달러, 6.26달러, 22.13달러, 4.65달러, 9.97달러가 모두 결제 완료 상태로 표시돼 있다.
2026년 3~7월 실제 결제 내역. 합계 47.32달러이며 5월 청구액이 가장 컸다.

청구 기간은 37월이고 분석 화면은 17월이라 두 자료의 기간이 일치하지 않는다. p50은 평균 실행 시간이 아니므로 1,527 × 255초로 총 사용 시간을 추정하지도 않았다. 이 기록으로 확정할 수 있는 것은 현재 규모의 실제 지출뿐이다.

CodeBuild와 Blacksmith의 선택이 갈리는 곳

판단 기준CodeBuild 쪽이 자연스러운 조건Blacksmith 쪽이 자연스러운 조건
소스와 워크플로GitLab·CodeCommit, CodePipeline이 기준GitHub 조직과 GitHub Actions가 기준
AWS 권한CodeBuild 서비스 역할로 계정 안에서 통제GitHub OIDC의 sub 조건으로 저장소·브랜치를 제한
사설 네트워크VPC 서브넷·보안 그룹으로 RDS·내부 ECS·사설 저장소 접근외부 러너 접근을 허용할 수 있고 OIDC·공개 AWS API로 배포
Docker 캐시AWS 안에서 캐시·Docker 이미지 서버를 운영저장소별 영속 캐시와 관리형 러너를 빠르게 붙임
운영 책임buildspec·IAM·CloudWatch·CodePipeline을 한 체계로 운영러너 프로비저닝·디스크·GC·대시보드를 공급자에게 맡김
규정과 공급자AWS 단일 공급자 경계가 중요별도 GitHub App과 외부 실행 공급자 심사가 가능

CodeBuild는 VPC ID, 서브넷과 보안 그룹을 프로젝트에 지정해 사설 RDS, ElastiCache, 내부 ECS와 사설 아티팩트 저장소에 접근한다.17 Blacksmith는 외부 서비스 접근용 고정 IP를 제공하지만 현재 공개 가격은 IP 하나에 월 100달러다.18 사설망 접근이 필수라면 러너 분당 가격보다 네트워크 설계와 보안 심사가 먼저다.

Blacksmith의 보안 문서는 SOC 2 Type 2, GDPR 준수, ISO 27001 데이터센터를 명시하고 작업마다 Firecracker microVM을 만든다고 설명한다. GitHub App은 워크플로 수정과 JIT 러너 토큰 발급에 필요한 권한을 요청한다.19 이 정보는 검토의 출발점이지 고객사 보안 심사를 대신하지 않는다.

비슷한 과제를 다루고 계신가요?기술 과제 검토 요청

우리가 Blacksmith를 선택한 기준

우리 환경의 소스와 코드 리뷰는 GitHub에 있다. Docker 이미지를 자주 만들어 ECR과 ECS로 보낸다. 소규모 팀이 Actions Runner Controller나 EC2 러너 풀의 스케일링, 패치, 디스크와 BuildKit GC까지 운영하는 것보다 관리형 실행 계층을 쓰는 편이 맞았다. 배포 권한은 GitHub OIDC로 짧게 열고 AWS 역할의 sub 조건을 저장소와 브랜치에 묶었다.

이 선택은 클라이언트 파이프라인에도 Blacksmith를 넣겠다는 뜻이 아니다. GitLab·CodeCommit, 사설 VPC, AWS 서비스 역할이 기준인 프로젝트에서는 CodePipeline과 CodeBuild를 유지한다. 실제로 소스와 빌드를 사설망 안으로 가져간 사례는 NKS 현대화의 GitLab·Jenkins 파이프라인에 따로 기록했다.

자사 환경에서는 GitHub Actions 파일을 거의 그대로 유지했고 Docker 캐시를 직접 운영하지 않았다. 작업·캐시·실패·비용도 한 대시보드에서 봤다. 6개월 지표는 이 구성이 작동한다는 운영 기록이다. 다른 러너보다 몇 배 빠르다는 증명은 아니다.

도입 전에 2주 실험으로 확인할 것

  1. Docker 비중이 큰 워크플로 두 개를 고르고 기존 러너의 p50·p95, 대기 시간, 성공률과 월 비용을 기록한다.
  2. 같은 커밋을 GitHub 제공 러너와 Blacksmith에서 반복해 콜드 캐시와 웜 캐시를 따로 비교한다.
  3. max-cache-size-mb로 Docker 캐시 상한을 정하고 캐시 적중률과 월 GB를 함께 본다. 캐시되지 않은 첫 단계, ECR 압축 이미지 크기와 가장 큰 변경 레이어도 기록한다.5
  4. Docker 단계, 전체 이미지 작업, CI 임계 경로와 러너 총사용 시간을 나눠 측정한다. 병렬화는 대기 시간을 줄여도 전체 실행 자원을 늘리기도 한다.
  5. AWS OIDC 역할의 audsub, GitHub App 권한, 외부 액션 버전 고정, 고정 IP 필요 여부를 검토한다.
  6. 무료 한도를 지출 상한으로 가정하지 말고 예산 경보와 중단 조건을 확인한다. 2026년에는 무료 한도 초과 뒤 1,081달러 청구서를 받았다는 공개 사례도 있었다.20

파일 한 줄을 바꾸는 도입은 쉽다. 판단은 그 다음부터다. 빌드가 빨라졌는지보다 리뷰가 기다리는 시간이 줄었는지, 분당 가격보다 성공한 변경 한 건을 운영팀 손대지 않고 통과시키는 비용이 낮아졌는지를 봐야 한다.

자주 묻는 질문

Blacksmith는 무엇인가

Blacksmith는 GitHub Actions용 관리형 러너다. 워크플로 제어는 GitHub가 맡고 Blacksmith는 격리된 실행 환경과 콜로케이션 캐시, Docker 레이어 캐시, CI Analytics를 제공한다. GitHub 조직에서 runs-on 태그를 바꾸는 방식으로 도입한다.

Blacksmith가 AWS CodeBuild를 대체할 수 있나

항상 그렇지는 않다. GitHub Actions가 기준이고 러너 운영을 줄이려면 Blacksmith가 맞다. GitLab·CodeCommit, CodePipeline, VPC 내부 접근과 AWS 서비스 역할이 기준이면 CodeBuild가 더 단순하다. 둘은 같은 위치의 제품이라기보다 서로 다른 제어면에 붙는 실행 계층이다.

Blacksmith에서 ECR로 이미지를 보내고 ECS를 배포할 수 있나

가능하다. GitHub Actions에서 AWS OIDC로 제한된 IAM 역할을 인수하고 ECR 이미지 전송과 ECS 배포 권한을 준다. 장기 AWS 액세스 키를 GitHub Secret에 저장하지 않고 역할의 sub 조건으로 허용 저장소와 브랜치를 좁히는 것이 핵심이다.

Blacksmith의 속도를 직접 구성으로 재현할 수 있나

핵심 원리는 재현 가능하다. 영속 볼륨을 가진 원격 BuildKit 데몬과 가까운 캐시를 두면 임시 러너에서도 캐시를 재사용한다. 대신 GC, 동시 빌드, 격리, 패치, 장애 복구와 비용 관측을 직접 운영해야 한다. Blacksmith의 가치는 캐시 원리보다 실행 계층을 운영해 주는 데 있다.


GitHub 기반 애플리케이션의 CI 병목을 측정하거나 CodeBuild·관리형 러너·자체 BuildKit의 경계를 정해야 한다면 클라우드 & 인프라에서 현재 워크플로와 AWS 네트워크부터 함께 검토한다. AWS 내부 트래픽과 ECR 비용 경로는 AWS 보이지 않는 비용에서 더 자세히 다룬다.

참고 자료

가격과 기존 제품 동작은 2026년 7월 23일 공개 페이지를 확인했다. Docker 캐시 키·LWW·GitHub Actions 동시성·빌드 기록 동작은 2026년 8월 12일 다시 확인했다. 801플래닛 수치는 조직 전체 대시보드, 결제 내역, 저장소별 GitHub Actions 실행 기록과 Blacksmith 작업 지표에서 읽었다. GitHub 제공 러너를 쓴 같은 커밋의 A/B 기준선과 CI 병렬화의 장기 표본은 이 글에 포함하지 않았다.

출처와 각주20개펼치기접기

Footnotes

  1. GitHub Docs, Configuring OpenID Connect in Amazon Web Services. 장기 자격증명 없이 AWS 역할을 인수하고 aud·sub 조건으로 범위를 제한하는 방법.

  2. Findy Tools, Blacksmith で手軽に GitHub Actions を高速化&コスト削減. 공개 화면에서 제목과 작성자만 확인 가능했으며 본문 수치는 사용하지 않음.

  3. Blacksmith Docs, Quickstart. GitHub 조직 연동, 러너 태그 교체, GitHub 조직 전용 제한.

  4. Blacksmith Docs, CI Analytics. 작업 시간·실패율·캐시·저장소별 비용 화면.

  5. Blacksmith Docs, 40x Faster Docker Builds. 저장소별 Docker 레이어 캐시, max-cache-size-mb, LWW 동시성, 7일 미사용 캐시 제거와 $0.50/GB·월 가격. 2 3 4 5

  6. GitHub Docs, Control the concurrency of workflows and jobs. 같은 concurrency group에서 한 job만 실행하고 cancel-in-progress로 실행 중 작업의 취소 여부를 정하는 방법.

  7. Docker Docs, GitHub Actions build summary. Dockerfile, build duration, cache utilization과 내려받을 수 있는 build record 설명.

  8. Blacksmith, Pricing. Ubuntu x64 2 vCPU 분당 가격, 무료 분과 캐시·고정 IP 부가 가격. 2

  9. Aaditya Sondhi, Blacksmith, Reverse engineering GitHub Actions cache to make it fast, 2025-07-23. MinIO 콜로케이션 캐시와 114MB 다운로드 비교.

  10. John Howard, Fast GitHub Actions with Blacksmith, 2026-04-10. Agentgateway E2E 작업의 전환 전후 기록과 후원 공개.

  11. Javier Cabrera Arteaga, Remote buildkit agents to speed up Docker builds by 10 times, 2025-11-04. 영속 BuildKit 실험, Go 개선과 Node --load 회귀.

  12. AWS CLI, Amazon ECR describe-images. imageSizeInBytes는 레지스트리에 저장된 압축 이미지 크기이며 로컬 docker images의 압축 해제 크기와 다를 수 있다.

  13. Docker Docs, Optimize cache usage in builds. 변경이 적고 비용이 큰 단계를 먼저 배치하고, package manifest를 소스보다 먼저 복사하며, 빌드 컨텍스트를 줄이는 방법.

  14. Docker Docs, Multi-stage builds. builder stage에서 필요한 산출물만 final stage로 복사해 빌드 도구와 중간 파일을 제외하는 방식.

  15. GitHub Docs, Actions runner pricing. Linux 2코어 x64 분당 가격.

  16. AWS, AWS CodeBuild pricing. 온디맨드 분 단위 과금, general1.small 계산 예시, 무료 100분, 추가 비용과 Docker image server. 2

  17. AWS Docs, Use AWS CodeBuild with Amazon VPC. VPC·서브넷·보안 그룹 연결과 사설 리소스 접근.

  18. Blacksmith Docs, Static IPPricing. 조직 전용 WireGuard 터널과 고정 IP 가격.

  19. Blacksmith, Secure GitHub Actions, 2025-08-08 갱신. GitHub App 권한, JIT 토큰, Firecracker microVM 격리와 컴플라이언스 설명.

  20. Allen Pike, Forestwalk, Surprise! Pay $1000, 2026-06-08. 무료 한도 초과 뒤 계속 실행된 사용량과 청구 사례.

이 주제와 연결된 구축 서비스를 확인하세요.

클라우드 & 인프라

이런 작업을 실제 환경에 적용합니다.

엔지니어가 현재 환경과 제약을 먼저 검토하고, 필요한 경우 30분 기술 대화로 실행 범위를 정합니다.

이미 금융·헬스케어·미디어·공공의 팀들과 함께
기술 과제 검토 요청