Cloud Design 3rd - 100-hours-a-week/KTB4-1st-wiki GitHub Wiki

CD(์ง€์†์  ๋ฐฐํฌ) ์„ค๊ณ„

CI๋ฅผ ํ†ตํ•ด ์•ˆ์ •์ ์œผ๋กœ Docker ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์—ฌ GHCR์— ์ €์žฅํ–ˆ์œผ๋‹ˆ, ๊ตฌ๋™ ํ™˜๊ฒฝ์— ์ ‘์†ํ•ด์„œ ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋‚ด๋ฆฌ๊ณ  ์ƒˆ๋กœ ์˜ฌ๋ ค์•ผ ํ•œ๋‹ค.
์‚ฌ๋žŒ์ด ์ง์ ‘ ์ž‘์—…ํ•˜๋ฉด ํ•ญ์ƒ ์ผ๊ด€์„ฑ(๋™์ผํ•œ ์ ˆ์ฐจ์™€ ๊ฒ€์ฆ ๊ณผ์ •)์„ ๋ณด์žฅํ•˜๊ธฐ ์–ด๋ ต๊ณ , ๋ฐ˜๋ณต ์ž‘์—…์„ ๊ตณ์ด ์ˆ˜๋™์œผ๋กœ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ๋…ธ๋™๋„ ์ž์›์ธ ๋งŒํผ ํšจ์œจ์ ์ธ ์ž๋™ํ™”๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์ ์šฉ ๋ฒ”์œ„

  • ์„œ๋ฒ„ ๊ตฌ์„ฑ
    • ์šด์˜ ์„œ๋ฒ„ ๋‹จ์ผ EC2 ์ธ์Šคํ„ด์Šค
  • Docker Image ํƒœ๊ทธ ์ „๋žต
    • ์šด์˜ ์„œ๋ฒ„ ๋ฐฐํฌ์šฉ(main): Semantic Version(MAJOR.MINOR.PATCH) (์˜ˆ์‹œ: v1.0.1)
    • ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ ๊ฒ€์ฆ์šฉ(dev): dev-commit SHA, ์ตœ์‹  ๋ฒ„์ „์€ dev-latest
  • ๋ฐฐํฌ ๋‹จ์œ„
    • ํ”„๋ก ํŠธ์—”๋“œ, ๋ฐฑ์—”๋“œ, AI ๊ฐ๊ฐ ์„ธ ๊ฐœ์˜ Docker Image๋ฅผ Docker Compose๋กœ ๋ฌถ์–ด ๋ฐฐํฌ

๊ฐœ์š”

์„œ๋น„์Šค ์ค‘๋‹จ ํ—ˆ์šฉ ์—ฌ๋ถ€

  • 1์ฐจ ๋ฐฐํฌ์—์„œ๋Š” ๋ถ€ํŠธ์บ ํ”„ ๋‚ด์˜ ํ์‡„ ๊ทธ๋ฃน์—์„œ ๋จผ์ € ๋ฐฐํฌ๋˜๊ณ , ์‚ฌ์šฉ ์‹œ๊ฐ„์ด ์ผ์ •ํ•˜๋ฏ€๋กœ ์„œ๋น„์Šค์˜ ์ค‘๋‹จ์ด ๋ฐœ์ƒํ•ด๋„ ๊ดœ์ฐฎ๋‹ค.
  • ์„œ๋น„์Šค ์‚ฌ์šฉ ์‹œ๊ฐ„๋Œ€: ํ‰์ผ ์‰ฌ๋Š” ์‹œ๊ฐ„(9:00โ€“18:00 ์ค‘ ๋งค์‹œ 50๋ถ„โ€“์ •๊ฐ) + ์ ์‹ฌ์‹œ๊ฐ„(12:00โ€“13:00)

๋ฐฐํฌ ์ „๋žต

  • In-Place: ์ƒˆ ๋ฒ„์ „ ๋ฐฐํฌ ์‹œ ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘ ๋™์•ˆ ์„œ๋น„์Šค ์ค‘๋‹จ

๋ฐฐํฌ ์‹œ๊ฐ„

  • ์ •๊ทœ ๋ฐฐํฌ ์‹œ๊ฐ„: ๋งค์ฃผ ์›”์š”์ผ 10์‹œ
  • hotfix ๋ฐฐํฌ ์‹œ๊ฐ„: main merge CI ๋‹จ๊ณ„๊ฐ€ ๋๋‚œ ๋’ค ๊ณง๋ฐ”๋กœ ๋ฐฐํฌ

๋ฐฐํฌ ์ •์ฑ…

  • ํ™˜๊ฒฝ๋ณ„ ๋ฐฐํฌ ๋ฐฉ๋ฒ•

    • product
      • ๋งค์ฃผ ์›”์š”์ผ ์˜ค์ „ 9์‹œ Release Bundle ์ค‘ ๋ฐฐํฌํ•  ๋ฒ„์ „์„ ๋ฐฐํฌ์ž๊ฐ€ ์ง์ ‘ ์ง€์ •ํ•˜์—ฌ ์‹คํ–‰
        => (09:00-09:50) AI, BE, FE๊ฐ€ ๊ฐœ๋ณ„ ๋ ˆํฌ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด ์„œ๋น„์Šค ๊ทœ๊ฒฉ์ด ์ผ์น˜ํ•˜๋ฉฐ ๊ฒ€์ฆ๋œ ๋ฒ„์ „ ์กฐํ•ฉ ์ตœ์ข… ๊ฒ€ํ† ๋ฅผ ์„ ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
        => (09:30) ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ 10:00๋ถ€ํ„ฐ 5๋ถ„ ๋ฏธ๋งŒ(๋กค๋ฐฑ ํฌํ•จ)์˜ ๋‹ค์šดํƒ€์ž„์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ์„ ์ถฉ๋ถ„ํžˆ ๊ณ ์ง€ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.
    • test
      • ๋ณ„๋„ ๋ฐฐํฌ ์ž๋™ํ™”๊ฐ€ ํ•„์š” ์—†๋‹ค.
      • Git SHA ํƒœ๊ทธ์™€ latest ํƒœ๊ทธ๋กœ ๊ตฌ์„ฑ๋œ docker ์ด๋ฏธ์ง€๋ฅผ ๋กœ์ปฌ์—์„œ pull ๋ฐ›์•„ docker-compose.yml ํŒŒ์ผ์„ ํ™œ์šฉํ•˜์—ฌ ์‹คํ–‰
  • Release Bundle

    • ์ธํ”„๋ผ ๊ด€๋ฆฌ ๋ ˆํฌ์— ์ฆ‰์‹œ ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ๊ฐ ์ปจํ…Œ์ด๋„ˆ ๋ฒ„์ „์˜ ์กฐํ•ฉ์„ ์ •์˜ํ•œ menifest ํŒŒ์ผ(releases/v0.0.0.yaml)์„ ์ €์žฅํ•œ๋‹ค.

    • ํŒŒ์ผ ์ƒ์„ฑ ๋ฐ ์ˆ˜์ •์„ ์œ„ํ•ด ์›Œํฌํ”Œ๋กœ์šฐ ๊ฐ ๋ ˆํฌ์˜ ๋ฐฐํฌํ•  ๋ฒ„์ „ ํƒœ๊ทธ์™€ ๋ฆด๋ฆฌ์ฆˆ ๋ฒ„์ „์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ž…๋ ฅํ•˜๋ฉด GitHub Actions ๋Ÿฌ๋„ˆ๊ฐ€ ์ž๋™ ์ž…๋ ฅ(ํœด๋จผ ์—๋Ÿฌ ๋ฐฉ์ง€)

    • ๋ฒˆ๋“ค์— ํฌํ•จ๋œ ๊ฐ ์ด๋ฏธ์ง€๊ฐ€ GHCR์— ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€ Docker Registry API๋กœ ping์„ ๋‚ ๋ ค ํ™•์ธ ์ ˆ์ฐจ ํ•„์ˆ˜

    • release/v1.1.0.yaml
        release_metadata:
          bundle_version: "v1.1.0"
          release_date: "2026-09-09T10:00:00+09:00"
          released_by: "janna"
          target_environment: "production"
          description: "์ •๊ธฐ ๋ฆด๋ฆฌ์ฆˆ (์ฑ„ํŒ… ์•ˆ์ •ํ™” ๋ฐ AI ๊ฒ€์ฆ API ์ตœ์ ํ™”)"
        # ๊ฐ ์„œ๋น„์Šค๋ณ„ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋ฐ Git ์—ญ์ถ”์  ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
        services:
          backend:
            service_name: "springboot"
            image_uri: "ghcr.io/ktb-market/market-backend"
            image_tag: "v1.1.2"
            image_digest: "sha256:7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
            git_commit_sha: "a1b2c3d4e5f67890123456789abcdef012345678"
            git_commit_short: "a1b2c3d"
            git_ref: "refs/tags/v1.1.2"
            built_at: "2026-09-08T18:20:11Z"
            ci_workflow_run_id: "1782390123"
      
          ai:
            service_name: "fastapi"
            image_uri: "ghcr.io/ktb-market/market-ai"
            image_tag: "v1.1.0"
            image_digest: "sha256:3a4b5c6d7e8f90123456789abcdef0123456789abcdef0123456789abcdef01"
            git_commit_sha: "f9e8d7c6b5a43210fedcba9876543210fedcba98"
            git_commit_short: "f9e8d7c"
            git_ref: "refs/tags/v1.1.0"
            built_at: "2026-09-07T14:15:30Z"
            ci_workflow_run_id: "1771239981"
  • workflow_dispatch

    • CD ์›Œํฌํ”Œ๋กœ์šฐ ์‹คํ–‰ ์‹œ GHCR์— ์ ์žฌ๋œ ํƒœ๊ทธ ์ค‘ ๋ฐฐํฌํ•  Release Bundle์˜ RELEASE_VERSION์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ˆ˜๋™ ์ž…๋ ฅ๋ฐ›์•„ ๋ฐฐํฌํ•œ๋‹ค.
    • ์˜ˆ์‹œ: RELEASE_VERSION=v1.0.0
      => [BACKEND_TAG:v1.0.2, AI_TAG:v1.0.1, FRONTEND_TAG:v1.0.0]๋ฅผ ํฌํ•จํ•œ๋‹ค.
  • ์Šน์ธ ์ •์ฑ…

    • Release Bundle ์ƒ์„ฑ ์‹œ BE, FE, AI ํŒŒํŠธ์˜ ๊ฐ ๋‹ด๋‹น์ž๋ฅผ ํฌํ•จํ•˜์—ฌ ์ตœ์†Œ 3๋ช… ์ด์ƒ์˜ ์Šน์ธ์„ ๋ฐ›์•„์•ผ ๋ณ‘ํ•ฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •
      => GitHub Environments์˜ ์›Œํฌํ”Œ๋กœ์šฐ ์Šน์ธ์ž๋ฅผ ์ง€์ •ํ•˜๋Š” ์„ค์ •์€ ์ผ๋ฐ˜ private ๋ ˆํฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
      => Release Bundle์€ ๊ฒ€์ฆ์„ ๋๋‚ธ ์ด๋ฏธ์ง€ ์กฐํ•ฉ์œผ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ ์–ธ์ œ๋“  ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ด๋‹ค.
    • ์Šน์ธ ๊ธฐ์ค€: ์„ ํƒ๋œ ๋ฒ„์ „, ์ง์ „ ๋ฐฐํฌ ๋Œ€๋น„ ๋ณ€๊ฒฝ์ , ๋ฉ€ํ‹ฐ ๋ ˆํฌ ๊ฐ„ ํ˜ธํ™˜
  • ์šด์˜ ๋ผ์ดํ”„์‚ฌ์ดํด

    [1๋‹จ๊ณ„: ๊ฐ ๋ ˆํฌ main ๋ณ‘ํ•ฉ]

    • FE, BE, AI ๊ฐœ๋ณ„ ๋ ˆํฌ์—์„œ ๊ธฐ๋Šฅ ์™„๋ฃŒ ์‹œ main์— ๋ณ‘ํ•ฉ (์ฃผ 3ํšŒ)
    • CI๊ฐ€ ๋Œ๋ฉฐ GHCR์— ๊ณ ์œ  ํƒœ๊ทธ๋กœ ์ด๋ฏธ์ง€ ์ ์žฌ (์ตœ๊ทผ 5๊ฐœ ์œ ์ง€)

    [2๋‹จ๊ณ„: ์ •๊ธฐ ๋ฐฐํฌ ์ค€๋น„ (์›”์š”์ผ 08:30)]

    • ์ธํ”„๋ผ ๋‹ด๋‹น์ž๊ฐ€ create-release-manifest ์›Œํฌํ”Œ๋กœ์šฐ ์‹คํ–‰
    • ์ž๋™์œผ๋กœ release/v1.1.0 ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ๋ฐ PR ์˜คํ”ˆ

    [3๋‹จ๊ณ„: PR ๋ฆฌ๋ทฐ ๋ฐ ์ˆ˜์ •]

    • ํŒ€์›๋“ค(BE, FE, AI ๋ฆฌ๋“œ)์ด PR ์ฝ”๋ฉ˜ํŠธ ๋ฐ ๋ณ€๊ฒฝ ๋‚ด์—ญ ํ™•์ธ
    • [์ˆ˜์ • ๋ฐœ์ƒ ์‹œ]: ์›Œํฌํ”Œ๋กœ์šฐ ์žฌ์‹คํ–‰์œผ๋กœ PR ๋ธŒ๋žœ์น˜ ์ž๋™ ๊ฐฑ์‹ 
    • ๊ฐ ํŒŒํŠธ๋ณ„ 1๋ช…์„ ํ•„์ˆ˜๋กœ ํฌํ•จํ•˜์—ฌ 3๋ช… ์ด์ƒ ์Šน์ธ ์‹œ main์— ๋ณ‘ํ•ฉ

    [4๋‹จ๊ณ„: ์‹ค์ œ ์šด์˜ ๋ฐฐํฌ (์›”์š”์ผ 10:00)]

    • CD ์›Œํฌํ”Œ๋กœ์šฐ ์‹คํ–‰: RELEASE_VERSION="v1.1.0" ์ง€์ •

    • ์ธํ”„๋ผ ๋ ˆํฌ์˜ main์— ๋จธ์ง€๋œ releases/v1.1.0.yaml์„ ๊ธฐ๋ฐ˜์œผ๋กœ EC2 ์ˆœ์ฐจ ๊ต์ฒด ๋ฐฐํฌ ์‹คํ–‰

๋ฐฐํฌ ์ „๋žต

In-Place: EC2 ์ธ์Šคํ„ด์Šค์—์„œ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ pull -> ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ ๋ฐ ์ œ๊ฑฐ -> ์ƒˆ๋กœ์šด ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
=> ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ๋งŒ ๋Œ€์ƒ

docker compose pull <service>
docker compose up -d --no-deps <service>
  • ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ๋ฐฉ์‹์€ ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•˜๊ณ , ํŠธ๋ž˜ํ”ฝ ๋ผ์šฐํŒ… ๋“ฑ ์ถ”๊ฐ€์ ์ธ ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์„ฑ์ด ํ•„์š”ํ•˜๋‹ค.
  • 1์ฐจ ๋ฐฐํฌ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ 30๋ช…์œผ๋กœ ํ•œ์ •์ ์ด๊ณ , ์‚ฌ์ „์— ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ถฉ๋ถ„ํžˆ ๊ณ ์ง€(๋””์Šค์ฝ”๋“œ)๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ์— ์ž ์‹œ ๋™์•ˆ์˜ ์ค‘๋‹จ์œผ๋กœ ์ธํ•œ ๋ฆฌ์Šคํฌ๋Š” ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ์— ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค ๋Œ€๋น„ ๋งค์šฐ ์ ๋‹ค.

๋ฐฐํฌ ๊ฒ€์ฆ

  1. Docker ์—”์ง„ ๋ ˆ๋ฒจ Health Check(๊ธฐ๋™ ์—ฌ๋ถ€ ํ™•์ธ)
    • docker-compose.yml์— ์ •์˜ํ•œ healthcheck ์ •์ฑ…์— ์˜ํ•ด ์ˆ˜ํ–‰
  2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ค€๋น„ ์ƒํƒœ ํ™•์ธ
    • Spring Boot Actuator ๋‚ด๋ถ€ ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‚ด๋ถ€ ์˜์กด์„ฑ(DB) ์ •์ƒ ์ˆ˜๋ฆฝ ๊ฒ€์ฆ
  3. ์™ธ๋ถ€ Nginx ๋ผ์šฐํŒ… ํฌํŠธ(443/80)๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค ์ง„์ž…๋กœ ์œ ํšจ์„ฑ ๊ฒ€์ฆ
    • 5XX Status Code ๋ฐ˜ํ™˜ ์‹œ ์‹คํŒจ

Rollback

  • ์ž๋™ ๋กค๋ฐฑ: ๊ฒ€์ฆ ์‹คํŒจ(Timeout ๋“ฑ) ์‹œ ์Šคํฌ๋ฆฝํŠธ ๋ ˆ๋ฒจ์—์„œ ์ˆ˜ํ–‰
    1. Release Bundle์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ฒ„์ „ ์•„๋ž˜๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
    2. ์ •๋ ฌ๋œ ์ˆœ์„œ๋Œ€๋กœ ์ตœ๋Œ€ 4๋ฒˆ๊นŒ์ง€ ๋ฒ„์ „์„ ํ•˜ํ–ฅํ•˜์—ฌ ์‹œ๋„
      => ์ผ์ฃผ์ผ์— ์ตœ๋Œ€ 3๊ฐœ ๋ฒ„์ „์ด ์ƒ์„ฑ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜์–ด ์ด์ „ ์ฃผ์ฐจ์˜ ์•ˆ์ •๋œ ๋ฐฐํฌ ๋ฒ„์ „์ด ์žฌ์‹œ๋„ 4ํšŒ์ฐจ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์ ์šฉ
  • ์ˆ˜๋™ ๋กค๋ฐฑ: CD ์›Œํฌํ”Œ๋กœ์šฐ Release Bundle ๋ฒ„์ „์„ ํ•˜ํ–ฅ ์กฐ์ •ํ•˜์—ฌ ์‹คํ–‰

Secret ๊ด€๋ฆฌ ์ „๋žต

GitHub Secrets์— ์˜ฌ์ธ

  • ์„œ๋น„์Šค์— ๊ฐœ์ธ ์ •๋ณด ๋“ฑ ๋ฏผ๊ฐ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์•„์„œ ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ์ˆ˜์ค€์ด ์š”๊ตฌ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ƒ์—…์ ์ธ ์„œ๋น„์Šค๊ฐ€ ์•„๋‹ˆ๋ผ์„œ ํ•ด์ปค์—๊ฒŒ ์œ„ํ˜‘์„ ๋ฐ›์„ ์œ„ํ—˜์ด ๋งค์šฐ ์ ๋‹ค.
โš ๏ธ **GitHub.com Fallback** โš ๏ธ