Skip to content

deploy 가 CI 빌드 JAR 을 재사용해 중복 빌드 제거#753

Merged
sevineleven merged 5 commits into
devfrom
infra/deploy-reuse-ci-jar
Jul 16, 2026
Merged

deploy 가 CI 빌드 JAR 을 재사용해 중복 빌드 제거#753
sevineleven merged 5 commits into
devfrom
infra/deploy-reuse-ci-jar

Conversation

@sevineleven

@sevineleven sevineleven commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Situation

  • 배포가 약 4-5분 걸려 단축 지점을 조사하던 중, CI 와 deploy 가 같은 커밋의 JAR 을 두 번 빌드하는 중복을 발견했다.
  • CI 의 build 잡은 push·PR 마다 JAR 을 만들지만 어디에도 쓰지 않고 버린다. deploy 는 그 뒤 같은 커밋 JAR 을 다시 빌드한다(약 47초).

Task

  • deploy 단계의 재빌드를 없애 배포를 단축한다.
  • 핵심 고민: 재사용할 JAR 이 "지금 배포하는 그 커밋" 의 것임을 어떻게 보장하나. 엉뚱한 커밋의 JAR 을 집는 레이스를 막아야 한다.

Action

재사용 배선

  • CI build 잡이 만든 JAR 을 아티팩트로 올리고, deploy 는 자기를 트리거한 CI 실행의 아티팩트를 받아 재빌드를 건너뛴다.
트리거 JAR 확보 러너 JDK/Gradle
자동 (workflow_run) 트리거한 CI 실행의 아티팩트 다운로드 불필요 (스킵)
수동 (workflow_dispatch) 러너에서 직접 빌드 (fallback) 필요
  • 커밋 못박기: deploy 는 그 배포를 트리거한 CI 실행의 id 를 안다. 그 실행의 아티팩트만 집어 "배포 커밋 = JAR 커밋" 을 보장한다. 그냥 최신 아티팩트를 집으면 배포 도중 다른 push 로 커밋이 어긋난다.
  • 아티팩트 항상 존재: deploy 자동 트리거 조건은 "dev/staging/main push CI 성공" 하나뿐이고, 그 push CI 는 항상 빌드와 업로드를 돈다. 업로드가 실패하면 CI 가 실패해 deploy 자체가 안 트리거되므로, "deploy 는 도는데 JAR 이 없는" 경우가 생기지 않는다.
  • 수동배포 fallback: workflow_dispatch 는 트리거한 CI 가 없어 아티팩트도 없다. 이때만 러너에서 기존처럼 빌드한다. 자동 경로는 러너에 JDK·Gradle 이 필요 없다 - 도커 빌드의 layertools extract 는 이미지 안에서 돈다.

plain jar 함정 제거

  • 러너의 assemble 은 실행용 boot jar 와 라이브러리용 plain jar 를 함께 만든다. build/libs 에 jar 가 2개면 배포·CI 의 COPY build/libs/*.jar 가 어느 jar 인지 모호해져 깨진다.
  • plain jar 를 비활성해 산출물을 boot jar 하나로 고정했다. 기존 deploy 는 boot jar 만 만들어 1개라 안 걸렸으나, assemble 산출물을 그대로 넘기면 걸린다.

실패 가시성

  • 자동 경로의 새 실패 지점(아티팩트 다운로드)을 배포 요약표와 Discord 알림에 반영했다.
  • 요약표의 "Gradle 빌드" 행은 빌드·다운로드 중 실제 실행된 쪽을 보여주는 "JAR 준비" 로 바꿨다.

Docker 빌드 최적화 (전 환경 공통)

  • 러너가 arm64 네이티브(배포 arm64 러너 전환 (QEMU 에뮬레이션 제거) #749)라 크로스빌드가 불필요해, 이미지 빌드를 buildx(build-push-action)에서 기본 docker 데몬의 plain docker build+push 로 바꿔 setup-buildx 스텝(약 10초)을 없앴다. 결과는 동일한 arm64 네이티브 이미지다.
  • JAR 재사용은 dev 자동배포 한정이지만, 이 Docker 빌드 스텝은 dev 와 promote(staging·prod)가 모두 타므로 buildx 제거는 전 환경에 적용된다. 로컬 docker build 로 Dockerfile.ci 멀티스테이지(layertools extract + runtime) 전체를 실증했다(결과 arm64 확인).
  • 아티팩트 업로드는 store(compression-level 0)로 둔다. JAR 은 이미 압축된 zip 이라 재압축이 크기 이득 없이 CPU 만 쓴다.

Result

  • dev push 자동배포: 약 60초 절감(JAR 재빌드 47초·JDK 4초·Gradle 캐시 9초를 걷어내 재사용 + buildx 셋업 10초 제거, 다운로드 5-10초 추가).
  • promote(staging·prod) 배포: JAR 재사용은 안 되지만(workflow_dispatch 라 fallback 빌드, 정확), buildx 제거가 공통 스텝이라 적용돼 약 10초 절감. 승격 가속의 정석인 이미지 승격(dev 가 이미 빌드·push 한 이미지 재사용)은 prod 경로를 건드리는 별도 작업이다.
  • 라이브 검증 구분: buildx 제거는 로컬 docker build 로 이미 실증(arm64). JAR 크로스런 다운로드는 workflow_run 이벤트를 로컬 재현 못 해 문법·권한·로직만 사전 확인하고 머지 후 첫 dev 배포에서 확정된다.
  • 실패해도 무중단: 다운로드는 blue-green 전환 전(잡 초반)이라, 실패 시 돌던 앱이 그대로 유지되고 원인이 알림에 "CI 아티팩트 다운로드 실패" 로 표시된다.
  • 남은 단축 레버인 EC2 파일 업로드(SCP) 합치기(약 25-30초)는 provision 스크립트가 업로드 경로를 하드코딩해 결합이 있어, 별도 PR 로 분리한다.

연관 이슈

Summary by CodeRabbit

  • 배포 개선
    • CI에서 push 이벤트일 때에만 애플리케이션 JAR을 app-jar 아티팩트로 업로드(3일 보관)하고, 누락 시 실패하도록 했습니다.
    • 배포에서는 자동/수동 흐름에 따라 JAR 재사용 또는 빌드 수행을 분기했습니다.
    • 배포 요약/실패 알림이 아티팩트 수집 실패를 정확히 반영하도록 수정했습니다.
  • 빌드/산출물
    • “plain jar” 생성을 비활성화해 부트 JAR만 단일 산출물로 고정했습니다.
  • 기타
    • Docker 이미지를 빌드/푸시 방식이 변경되었습니다.

CI(assemble)와 deploy(bootJar)가 같은 커밋 JAR 을 두 번 빌드하던 중복을 없앤다.
CI build 잡이 JAR 을 아티팩트로 올리고, deploy 는 자기를 트리거한 CI 실행(run-id)의
아티팩트를 받아 재빌드(약 47초)를 건너뛴다. run-id 로 못박아 배포 커밋과 다른 커밋의
JAR 을 집는 레이스를 차단한다. 수동배포(workflow_dispatch)는 트리거 CI 가 없어
기존 빌드로 fallback 한다.

- build.gradle.kts: plain jar 비활성 — assemble 이 jar 2개를 만들면 COPY build/libs/*.jar
  가 모호해져 깨진다. boot jar 하나로 고정.
- ci.yml: push 일 때 build/libs/*.jar 를 app-jar 로 업로드(3일 보존).
- deploy.yml: actions:read 추가, 자동배포=아티팩트 다운로드/수동배포=빌드 fallback,
  실패 알림·요약표에 다운로드 실패 케이스 반영.
@sevineleven sevineleven added the infra 운영 환경 (IaC·클라우드 리소스·secret·배포 workflow) label Jul 15, 2026
@sevineleven sevineleven self-assigned this Jul 15, 2026
@github-actions

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Gradle에서 plain JAR 생성을 비활성화하고, CI가 push 시 단일 JAR을 아티팩트로 업로드하도록 변경했다. 자동 배포는 해당 아티팩트를 다운로드하며, 수동 배포만 로컬 빌드를 수행한다. Docker 배포 방식과 실행 결과 보고도 경로별로 갱신했다.

Changes

JAR 아티팩트 기반 배포

Layer / File(s) Summary
단일 JAR 산출물 고정
build.gradle.kts
Spring Boot의 plain JAR 생성을 비활성화해 실행용 boot JAR만 생성되도록 설정했다.
CI JAR 아티팩트 업로드
.github/workflows/ci.yml
push 이벤트에서 build/libs/*.jarapp-jar로 업로드하고, 3일 보관 및 파일 누락 시 실패를 적용했다.
자동·수동 배포 경로 분기
.github/workflows/deploy.yml
workflow_run은 CI run의 아티팩트를 다운로드하고, workflow_dispatch는 JDK 설정과 bootJar 빌드를 수행하도록 분기했다.
Docker 배포 및 결과 보고
.github/workflows/deploy.yml
Docker 이미지 빌드·푸시를 셸 명령으로 변경하고, JAR 다운로드 실패를 배포 요약과 Discord 실패 원인에 반영했다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Gradle
  participant CI_build_job
  participant Artifact_store
  participant Deploy_workflow
  participant Container_registry
  Gradle->>CI_build_job: assemble로 boot JAR 생성
  CI_build_job->>Artifact_store: push 시 app-jar 업로드
  Deploy_workflow->>Artifact_store: workflow_run의 run-id로 app-jar 다운로드
  Artifact_store-->>Deploy_workflow: JAR 반환
  Deploy_workflow->>Gradle: workflow_dispatch에서만 bootJar 실행
  Deploy_workflow->>Container_registry: docker build 및 docker push 실행
Loading
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch infra/deploy-reuse-ci-jar

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

49-51: 🩺 Stability & Availability | 🔵 Trivial

아티팩트 수명과 자동 배포 복구 정책이 맞지 않을 수 있습니다.

  • .github/workflows/ci.yml#L49-L51: retention-days를 자동 재배포·롤백 SLA 이상으로 설정하거나, 3일 제한이 운영 정책임을 명시하세요.
  • .github/workflows/deploy.yml#L150-L180: app-jar 만료·누락 시 JDK/Gradle 기반 자동 fallback을 추가하거나, 해당 경우 수동 배포가 필요하다는 복구 절차를 명확히 하세요.

GitHub Actions 아티팩트는 보관 기간이 지나면 만료되므로, 현재 구조에서는 오래된 자동 배포 재시도가 실패할 수 있습니다. (github.com)

As per path instructions, .github/workflows/**의 concurrency 설정과 운영 리스크를 우선 검토해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 49 - 51, 아티팩트 보관 기간과 자동 재배포·롤백 SLA를
일치시키세요. .github/workflows/ci.yml 49-51의 app-jar 보관 기간을 운영 정책에 맞게 늘리거나 3일 제한이
정책임을 명시하고, .github/workflows/deploy.yml 150-180의 app-jar 만료·누락 경로에는 JDK/Gradle
기반 자동 fallback을 추가하거나 수동 배포가 필요하다는 복구 절차를 명확히 하세요. 관련 workflow의 concurrency 설정과
재배포·롤백 운영 리스크도 함께 검토하세요.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 49-51: 아티팩트 보관 기간과 자동 재배포·롤백 SLA를 일치시키세요. .github/workflows/ci.yml
49-51의 app-jar 보관 기간을 운영 정책에 맞게 늘리거나 3일 제한이 정책임을 명시하고,
.github/workflows/deploy.yml 150-180의 app-jar 만료·누락 경로에는 JDK/Gradle 기반 자동
fallback을 추가하거나 수동 배포가 필요하다는 복구 절차를 명확히 하세요. 관련 workflow의 concurrency 설정과 재배포·롤백
운영 리스크도 함께 검토하세요.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1334ca0b-6a2f-4693-bd1b-2c41c28f40d2

📥 Commits

Reviewing files that changed from the base of the PR and between e2f6213 and f9cc5fe.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • .github/workflows/deploy.yml
  • build.gradle.kts

@github-actions github-actions Bot requested a review from m-a-king July 15, 2026 17:11
CodeRabbit nitpick 대응. 롤백·재배포가 옛 아티팩트에 의존하지 않음(자동=새 push,
수동=러너 빌드 fallback, blue-green=컨테이너 유지)을 주석으로 self-documenting.
@sevineleven

Copy link
Copy Markdown
Collaborator Author

CodeRabbit nitpick (ci.yml 아티팩트 retention-days) 대응 — 5bf6c0a.

3일 보존은 안전합니다. 아티팩트를 옛 것으로 소비하는 경로가 없어서입니다:

  • 자동배포(workflow_run)는 새 push 마다 새 CI 라 항상 갓 만든 아티팩트를 수분 내 소비
  • 수동 재배포(workflow_dispatch)는 아티팩트가 아니라 러너 빌드 fallback 경로
  • blue-green 롤백은 돌던 컨테이너를 유지(옛 이미지·JAR 재취득 안 함)

이 안전 근거가 주석에 없어 혼동을 준 것이라, 근거를 ci.yml 업로드 스텝 주석에 명시해 self-documenting 으로 만들었습니다.

JAR 은 이미 압축된 zip 이라 기본 level 6 재압축은 크기 이득 없이 CPU 만 쓴다.
store 로 업로드 CPU 를 아낀다. CI 는 deploy 가 workflow_run 으로 기다리는 크리티컬 패스.
러너가 arm64 네이티브(#749)라 크로스빌드가 불필요해, build-push-action(buildx)을
기본 docker 데몬의 plain docker build+push 로 바꿔 setup-buildx 스텝(약 10초)을 없앤다.
결과 이미지는 동일(arm64 네이티브). 로컬 docker build 로 Dockerfile.ci 전체 빌드 실증.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/deploy.yml (1)

150-158: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

actions/download-artifact를 v7로 올려 주세요.
이 단계는 자동 배포의 핵심 경로라서, actions/download-artifact@v4node20 런타임보다 v7node24 런타임으로 맞춰 두는 편이 안전합니다. 현재 run-idgithub-token 조합은 그대로 유지하면 됩니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy.yml around lines 150 - 158, Update the Download JAR
from triggering CI run step, identified by id fetch_jar, to use
actions/download-artifact@v7 instead of `@v4`. Preserve the existing run-id and
github-token configuration unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/deploy.yml:
- Around line 150-158: Update the Download JAR from triggering CI run step,
identified by id fetch_jar, to use actions/download-artifact@v7 instead of `@v4`.
Preserve the existing run-id and github-token configuration unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8154b77e-9629-4385-ad1a-7eb237da1bc9

📥 Commits

Reviewing files that changed from the base of the PR and between f6bad96 and 8a66662.

📒 Files selected for processing (1)
  • .github/workflows/deploy.yml

@sevineleven

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@sevineleven sevineleven merged commit 0f61bc7 into dev Jul 16, 2026
17 checks passed
@sevineleven sevineleven deleted the infra/deploy-reuse-ci-jar branch July 16, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

infra 운영 환경 (IaC·클라우드 리소스·secret·배포 workflow)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant