[26.03.25 / TASK-267] Chore - CD workflow 추가#52
Conversation
Walkthrough태그 푸시 및 수동 배포를 지원하도록 GitHub Actions CD를 추가/재구성하고, docker-compose.yml의 API 이미지 태그를 환경변수로 동적 처리하며, run.sh에 로그 팔로우 제어 플래그(-f)를 도입했습니다. (50단어 이내) Changes
Sequence DiagramsequenceDiagram
participant User as 개발자/태그 발행자
participant GHA as GitHub Actions
participant Build as build-and-push Job
participant DockerHub as Docker Hub
participant Deploy as deploy Job
participant Server as 배포 서버
participant Slack as Slack
User->>GHA: 태그 푸시(v*) 또는 수동 실행
GHA->>Build: 빌드/푸시 트리거 (태그 이벤트 시)
Build->>Build: API_VERSION 결정 (ref_name)
Build->>DockerHub: 이미지 빌드 & 푸시 (latest, 버전 태그)
DockerHub-->>Build: 푸시 완료
Build-->>GHA: 빌드 상태(성공/스킵/실패)
GHA->>Deploy: 배포 시작 (성공 또는 스킵 조건)
Deploy->>Deploy: API_VERSION 결정 (입력 or ref_name), 유효성 검사
Deploy->>Server: SSH 접속 → 태그/브랜치 체크아웃 → `bash run.sh` 실행
Server-->>Deploy: 배포 완료 응답
Deploy->>Slack: 성공/실패 알림 전송 (버전·액터·실행 링크)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/workflows/api-cd.yaml (1)
61-61:sed ... | bash패턴의 잠재적 취약성
run.sh를 sed로 필터링하여 bash에 파이프하는 방식은 동작하지만, 스크립트 변경 시 예상치 못한 동작이 발생할 수 있습니다.대안으로
run.sh에--no-logs플래그를 추가하거나 별도의 배포용 스크립트를 만드는 것을 고려해 주세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/api-cd.yaml at line 61, The workflow uses a brittle "sed '/docker compose logs -f/d' run.sh | bash" pattern which risks unexpected behavior when run.sh changes; modify run.sh to accept a flag like --no-logs (or create a dedicated deploy script) that disables the "docker compose logs -f" behavior, then update the workflow step to invoke the script directly (e.g., "bash run.sh --no-logs" or call the new deploy script) instead of filtering and piping via sed; update references in the workflow step that currently contain the sed pipeline and the run.sh script to use the new flag/script.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/api-cd.yaml:
- Around line 49-75: The current sequential SSH deployment steps "Deploy to
Server 1" and "Deploy to Server 2" may stop the second deploy if the first
fails; update the workflow to ensure resilience by either adding
continue-on-error: true to the failing-prone job steps (the two job steps named
"Deploy to Server 1" and "Deploy to Server 2") so a failure on one host doesn't
block the other, or refactor these into a matrix/strategy job that runs the same
ssh-action in parallel across hosts (use a matrix entry for
DEPLOY_HOST/DEPLOY_SSH_KEY pairs and the existing script block) so both servers
are deployed concurrently and independently.
- Around line 77-90: The workflow uses slackapi/slack-github-action@v1.24.0 in
the "Notify Slack on Success" and "Notify Slack on Failure" steps; update both
uses entries to slackapi/slack-github-action@v3.0.1 and then verify the action's
input/schema changes (e.g., payload format and environment variable names)
against the v3.0.1 docs to adjust the "payload" content and SLACK_WEBHOOK_URL
usage if required so the notifications continue to work.
---
Nitpick comments:
In @.github/workflows/api-cd.yaml:
- Line 61: The workflow uses a brittle "sed '/docker compose logs -f/d' run.sh |
bash" pattern which risks unexpected behavior when run.sh changes; modify run.sh
to accept a flag like --no-logs (or create a dedicated deploy script) that
disables the "docker compose logs -f" behavior, then update the workflow step to
invoke the script directly (e.g., "bash run.sh --no-logs" or call the new deploy
script) instead of filtering and piping via sed; update references in the
workflow step that currently contain the sed pipeline and the run.sh script to
use the new flag/script.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6bf2bfec-0b5b-476b-94dc-257d06b1e112
📒 Files selected for processing (3)
.github/workflows/api-cd.yaml.github/workflows/api-ci.yamldocker-compose.yml
six-standard
left a comment
There was a problem hiding this comment.
코드 잘 읽었습니다!
좋았던 점
- 입력값으로 롤백할 버전을 넣을 수 있는 점이 좋았습니다!
Nuung
left a comment
There was a problem hiding this comment.
좋았던 점
- tag 활용해 CI/CD 한 호흡까지 가져가고, CI랑 CD분리 하는 것도 너무 좋았어요.
- 이게 env 가 분리되면 더 깔끔해질 것 같아요!
아쉬운 점
- 코멘트 부분만 체크해주세요!
- x.y.z 으로 버저닝하는걸 시멘틱 버저닝이라고 하잖아요~ 여기에 대한 룰 하나 정도는 있어야 할 것 같아요. 뭘 바꾸면 x 를 바꾸고 뭘 바꾸면 y, 뭘 바꾸면 z 이지? 같은 내용이요.
- 버전 삭제의 경우 github tag 와 docker 버전 싱크가 안맞을 경우가 있을 것 같다는 리스크 정도/
.github/workflows/api-cd.yaml
Outdated
| - name: Deploy to Server 1 | ||
| uses: appleboy/ssh-action@v1 | ||
| with: | ||
| host: ${{ secrets.DEPLOY_HOST_1 }} | ||
| username: ${{ secrets.DEPLOY_USER }} | ||
| key: ${{ secrets.DEPLOY_SSH_KEY_1 }} | ||
| command_timeout: 10m | ||
| script: | | ||
| export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' | ||
| export API_VERSION=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} | ||
| cd ${{ secrets.DEPLOY_PATH }} | ||
| git pull origin main | ||
| sed '/docker compose logs -f/d' run.sh | bash | ||
|
|
||
| - name: Deploy to Server 2 | ||
| uses: appleboy/ssh-action@v1 | ||
| with: | ||
| host: ${{ secrets.DEPLOY_HOST_2 }} | ||
| username: ${{ secrets.DEPLOY_USER }} | ||
| key: ${{ secrets.DEPLOY_SSH_KEY_2 }} | ||
| command_timeout: 10m | ||
| script: | | ||
| export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' | ||
| export API_VERSION=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} | ||
| cd ${{ secrets.DEPLOY_PATH }} | ||
| git pull origin main | ||
| sed '/docker compose logs -f/d' run.sh | bash |
There was a problem hiding this comment.
matrix strategy 라는게 있는데, 이렇게 step 으로 쪼개지 말고 yaml 에서 특정 블록을 만들어서, 진행할 수 있거든요! 찾아보시면 좋을 것 같아요. 더욱이 server1 만 터지면 어쩌지? 라는 생각도 들어요.
There was a problem hiding this comment.
인사이트 감사합니다! matrix strategy 찾아보았는데 이런 이슈(matrix 값에 secrets 사용불가) 때문에 현재 스크립트에 적용은 어려울 것 같습니다.
그리고 matrix strategy를 사용하면 기본적으로 병렬 실행이 되는 것 같은데, 저희같이 무중단 배포 중인 경우에도 병렬 배포를 해도 괜찮나요??
There was a problem hiding this comment.
맞네요! 제가 디테일을 잘 못 생각했네요! 원래 방향 설계가 나을 것 같아요. @ooheunda
.github/workflows/api-cd.yaml
Outdated
| - name: Deploy to Server 1 | ||
| uses: appleboy/ssh-action@v1 | ||
| with: | ||
| host: ${{ secrets.DEPLOY_HOST_1 }} | ||
| username: ${{ secrets.DEPLOY_USER }} | ||
| key: ${{ secrets.DEPLOY_SSH_KEY_1 }} | ||
| command_timeout: 10m | ||
| script: | | ||
| export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' | ||
| export API_VERSION=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} | ||
| cd ${{ secrets.DEPLOY_PATH }} | ||
| git pull origin main | ||
| sed '/docker compose logs -f/d' run.sh | bash | ||
|
|
||
| - name: Deploy to Server 2 | ||
| uses: appleboy/ssh-action@v1 | ||
| with: | ||
| host: ${{ secrets.DEPLOY_HOST_2 }} | ||
| username: ${{ secrets.DEPLOY_USER }} | ||
| key: ${{ secrets.DEPLOY_SSH_KEY_2 }} | ||
| command_timeout: 10m | ||
| script: | | ||
| export GIT_SSH_COMMAND='ssh -i ~/.ssh/velog-dashboard-v2-api' | ||
| export API_VERSION=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} | ||
| cd ${{ secrets.DEPLOY_PATH }} | ||
| git pull origin main | ||
| sed '/docker compose logs -f/d' run.sh | bash |
There was a problem hiding this comment.
사견으로 이거 그냥 스크립트만 실행하게 그냥 run.sh 를 바꾸든, 자동 배포용 스크립트를 만들든 하는게 가장 좋을 것 같아요
추가적인 사견
https://www.notion.so/nuung/26-01-28-1be6299fd666805d873ad181123e30b7
|
| # dockerfile: Dockerfile | ||
| # image: velog-dashboard-v2-api | ||
| image: nuung/velog-dashboard-v2-api:latest | ||
| image: nuung/velog-dashboard-v2-api:${API_VERSION:-latest} |
There was a problem hiding this comment.
제가 가물가물해서 그런데 이 환경변수 깃헙에서 자동으로 tag 버전 가져오는거 맞나요? 저는 GITHUB_REF_NAME 를 썻었던 것 같아서
Jihyun3478
left a comment
There was a problem hiding this comment.
코멘트가 너무 늦어져서 죄송해요🥲 고생하셨습니다!!
좋았던 점
- CI와 CD를 각각의 파일로 분리해주셔서 각 워크플로우의 책임이 명확해진 부분이 좋았습니다.
- 성공 및 실패 시 Slack 알림이 오도록 추가해주신 부분이 좋았습니다!
궁금한 점
- 현재 API_VERSION 환경변수를 export로 설정한 뒤 docker-compose.yml에서 참조하는 구조인데, 해당 변수가 실제로 잘 전달되고 있는지 여쭤보고 싶습니다!
@Jihyun3478 일단 테스트상으론 문제 없긴 했습니다! 말씀주셔서 다시 검토해보니 괜찮을 것 같습니다! |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/api-cd.yaml:
- Around line 59-60: The workflow currently always runs "git pull origin main"
which mixes the selected image tag with whatever is currently on main; instead,
fetch the repo and checkout the exact ref you intend to deploy (the tag or
commit referenced by the workflow) before running docker-compose/run.sh. Replace
the unconditional "git pull origin main" steps with a fetch + checkout sequence
that uses the workflow's deployment ref variable (e.g., the tag or
GITHUB_REF/GITHUB_SHA or the action input you use for rollbacks) so the working
tree matches the image version, and ensure the checkout is forced/clean to avoid
leftover changes.
- Line 55: 현재 설정된 command_timeout 값을 늘리거나 헬스체크 재시도 예산을 줄여 SSH 타임아웃 문제를 해결하세요: CI
워크플로의 command_timeout 설정(현재 10m)을 15m 이상으로 변경(워크플로의 모든 command_timeout 항목에
적용)하거나, 대신 run.sh 스크립트에서 호출되는 wait_for_service 함수의 재시도 횟수/초기 지연 시간을 낮춰 헬스체크 총 소요
시간을 줄이세요(문제가 되는 wait_for_service 호출을 수정).
- Around line 8-11: The workflow accepts a raw input named "version" and injects
it unescaped into shell commands and JSON payloads, creating shell-injection and
JSON-break risks; fix by quoting the variable when used in shell (e.g., export
API_VERSION="${{ inputs.version }}" in the step that sets it) and/or add a
dedicated validation step that uses a strict regex (semantic-version or
allowed-pattern) to validate/normalize inputs and then expose the validated
value as a step output which all downstream steps (the ones currently inserting
the version into commands and JSON) must consume instead of the raw
inputs.version; ensure all JSON payload assembly also uses the validated value
and proper quoting/escaping.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0a214871-19c9-4040-8112-37db681db0cb
📒 Files selected for processing (2)
.github/workflows/api-cd.yamlrun.sh
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
.github/workflows/api-cd.yaml (1)
59-72:⚠️ Potential issue | 🟡 Minor
git checkout실패 가능성에 대비하세요.현재
git checkout "$API_VERSION"이 로컬 변경사항이 있을 경우 실패할 수 있습니다. 배포 서버에서 예기치 않은 파일 수정이 있을 때 배포가 중단될 수 있으므로, 강제 체크아웃을 고려하세요.♻️ 강제 체크아웃 적용 예시
git fetch --tags - git checkout "$API_VERSION" + git checkout -f "$API_VERSION"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/api-cd.yaml around lines 59 - 72, The deployment script's git checkout step (git checkout "$API_VERSION") can fail if there are local changes; update the script block to perform a forced, clean checkout before running run.sh by fetching tags, forcing checkout of "$API_VERSION" (or resetting to the remote ref) and removing untracked files so local modifications won't block deployment—locate the script section containing git fetch --tags and git checkout "$API_VERSION" and replace the checkout with a robust sequence that forces the branch/tag and cleans untracked files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/api-cd.yaml:
- Around line 74-87: The "Deploy to Server 2" step (uses:
appleboy/ssh-action@v1) currently runs git checkout "$API_VERSION" without
forcing; update the script in that step to use a forced checkout (git checkout
-f "$API_VERSION") just like the Server 1 change so uncommitted changes don't
block deployment — locate the "Deploy to Server 2" step and replace the git
checkout command in its script block accordingly.
---
Duplicate comments:
In @.github/workflows/api-cd.yaml:
- Around line 59-72: The deployment script's git checkout step (git checkout
"$API_VERSION") can fail if there are local changes; update the script block to
perform a forced, clean checkout before running run.sh by fetching tags, forcing
checkout of "$API_VERSION" (or resetting to the remote ref) and removing
untracked files so local modifications won't block deployment—locate the script
section containing git fetch --tags and git checkout "$API_VERSION" and replace
the checkout with a robust sequence that forces the branch/tag and cleans
untracked files.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f3ecc109-4f01-4b00-a0f6-bbe34107283a
📒 Files selected for processing (1)
.github/workflows/api-cd.yaml


🔥 변경 사항
버저닝을 포함한 CD workflow를 추가하였습니다.
git tag v${버전}git push origin v${버전}🏷 관련 이슈
X
📸 스크린샷 (UI 변경 시 필수)
X
📌 체크리스트
Summary by CodeRabbit
Chores
New Features