CD - 100-hours-a-week/21-iceT-wiki GitHub Wiki
1. ๋ฐฐํฌ ์๋ ๋ฐ ์ ํ์ฑ ํฅ์
- ๊ธฐ์กด Koco ์๋น์ค์๋ ๋ก์ปฌ ๋น๋ โ SCP ์ ์ก ๋ฐ SSH ์ ์ โ ์๋ ์ฌ์์ ๋ฑ ์ฌ๋ฌ ๋จ๊ณ๋ฅผ ์ฌ๋์ด ์ง์ ์ํ
- ์ด ๊ณผ์ ์์ ์ค์ ๊ฐ๋ฅ์ฑ์ด ์กด์ฌํ๊ณ , ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆผ (์ฝ 30๋ถ ์์)
- CD ํ์ดํ๋ผ์ธ์ ํตํด ๋ฐฐํฌ ๊ณผ์ ์ ์๋ํํ๋ฉด, ํด๋ฆญ ํ ๋ฒ ๋๋ Git ํ๊ทธ ํธ์๋ง์ผ๋ก 3~5๋ถ ๋ด ์์ ์ ์ผ๋ก ๋ฐฐํฌ ๊ฐ๋ฅ
- ๋ํ, ๋งค์ผ ์๋ก์ด ์ฝํ ์ ๋ต ์ ๋ฐ์ดํธ, ์ฑ๋ด, ์ปค๋ฎค๋ํฐ ๊ธฐ๋ฅ์ ๊ฐ์ถ ๋ณธ ์๋น์ค๋ ๊ธฐ๋ฅ ๊ฐ๋ฐ์ ์์ฃผ ์ ๋ฐ์ดํธํ ํ์๊ฐ ์์ด, ๋น ๋ฅด๊ณ ์ ๋ขฐ์ฑ ์๋ ์๋ ๋ฐฐํฌ ์ฒด๊ณ๊ฐ ํ์ํ๋ค.
2. ๋ฌด์ค๋จ ์๋น์ค ์ด์
- ์๋น์ค๋ ๋งค์ผ ์ค์ 9์ 30๋ถ~10์ ์ฌ์ด๊ฐ ์ต๋ ํธ๋ํฝ ์๊ฐ๋(๋์ ์ ์์ ์ฝ 150๋ช ์์)
- ์ ๊ธฐ ๋ฐฐํฌ๋ ๊ธ์์ผ 18์๋ก ์ค์ ๋์ด ์์ง๋ง, ๋ฐฐํฌ ์คํจ ์ ๋ณต๊ตฌ๊ฐ ๋๋ฆฌ๋ฉด ์ฌ์ฉ์์๊ฒ ์ํฅ์ด ๊ฐ ์ ์์
- CD๋ฅผ ํตํด ํฌ์ค ์ฒดํฌ + ๋กค๋ฐฑ ์ ๋ต ํฌํจ๋ Blue-Green ๋ฐฐํฌ๋ฅผ ๊ตฌ์ฑํจ์ผ๋ก์จ(์ถํ ์นด๋๋ฆฌ ๋ฐฐํฌ ์ ์ฉ), ๋ฐฐํฌ ์ค์๋ ์๋น์ค ์ค๋จ ์์ด ์์ ์ ์ธ ์ ํ ๊ฐ๋ฅ
3. ์๋น์ค ์ ๋ขฐ๋ ํ๋ณด
- ํด์ค ์ ๊ณต ์๋น์ค๋ ์ ํ์ฑ๊ณผ ์ ๋ขฐ๊ฐ ํต์ฌ์ธ๋ฐ, ๋ฐฐํฌ ์ค๋ฅ๋ ์ฅ์ ๊ฐ ๋น๋ฒํ๋ฉด ์ฌ์ฉ์ ์ ๋ขฐ๊ฐ ๊ธ๊ฒฉํ ์ ํ๋จ
- ์๋ํ๋ CD ํ์ดํ๋ผ์ธ์ ํ ์คํธ, ํฌ์ค ์ฒดํฌ, ๋ชจ๋ํฐ๋ง๊น์ง ํฌํจํ์ฌ ๋ฐฐํฌ ์ดํ ์์ ์ฑ์ ํ๋ณดํ๊ณ , ์ด์ ์งํ ๋ฐ์ ์ ๋น ๋ฅด๊ฒ ๋์ ๊ฐ๋ฅํจ
4. ๊ฐ๋ฐ ํจ์จ์ฑ ํฅ์ ๋ฐ ๋ฐ๋ณต ๊ฐ๋ฅํ ๋ฐฐํฌ
- ์๋ ๋ฐฐํฌ๋ ๋ด๋น์๊ฐ ์์ผ๋ฉด ์คํ์ด ์ด๋ ต๊ณ , ์ฃผ์/๋ช ๋ น ์ค์๋ก ๋ฐฐํฌ ์ํ๊ฐ ๋ฌ๋ผ์ง ์ ์์
- CD๋ ๋๊ฐ ํด๋ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ ๋ฐ๋ณต ๊ฐ๋ฅํ ๋ฐฐํฌ ํ๊ฒฝ์ ์ ๊ณตํ์ฌ, ํ์ํฌ์ ์์ฐ์ฑ ํฅ์์ ๊ธฐ์ฌํจ
5. MVP ๋จ๊ณ์์์ ๋ฏผ์ฒฉํ ๋ฐ๋ณต ๊ฐ์ ์ ๊ฐ๋ฅํ๊ฒ ํจ
- ํ์ฌ๋ MVP ๋จ๊ณ๋ก, ๊ธฐ๋ฅ ๊ฐ์ ๊ณผ ์์ ์ด ๋น๋ฒํ๊ฒ ์ด๋ค์ง
- CD ํ์ดํ๋ผ์ธ์ ํตํด ์์ ๋ณ๊ฒฝ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ํ๊ณ ์ฆ์ ๋ฐฐํฌ ๊ฐ๋ฅ, ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ๋น ๋ฅด๊ฒ ๋ฐ์ํ๋ ์ ์์ผํ ๊ฐ๋ฐ/๋ฐฐํฌ ์ฌ์ดํด์ ๊ตฌ์ถํ ์ ์์
- ์คํ ์ด์ง ํ๊ฒฝ: ์๋ ๋ฐฐํฌ(Continuous Deployment) ์ ์ฉ
- ์ด์(ํ๋ก๋์ ) ํ๊ฒฝ: ์น์ธ ํ ๋ฐฐํฌ(Continuous Delivery) ๋ฐฉ์ ์ฑํ
-
์ด๊ธฐ: Blue-Green ๋ฐฐํฌ ์ ๋ต ์ ์ฉ
- ๊ธฐ์กด ์๋น์ค ๋ฒ์ (Green)์ ์ ์งํ ์ํ์์ ์๋ก์ด ๋ฒ์ (Blue)์ ๋ณ๋๋ก ๋ฐฐํฌ
- ๋ฐฐํฌ ์๋ฃ ํ ๊ฒ์ฆ์ ๊ฑฐ์ณ ํธ๋ํฝ์ ์๋ก์ด ๋ฒ์ ์ผ๋ก ์ ํ
- ์ค๋ฅ ๋ฐ์ ์ ์ฆ์ ๊ธฐ์กด ๋ฒ์ ์ผ๋ก ๋ณต๊ท ๊ฐ๋ฅ
-
์ถํ: ์นด๋๋ฆฌ ๋ฐฐํฌ ์ ๋ต ๋์
์์
- ์ด๊ธฐ์๋ ์ผ๋ถ ์ฌ์ฉ์์๊ฒ๋ง ์๋ก์ด ๋ฒ์ ์ ๋ ธ์ถํ์ฌ ์์ ์ฑ์ ๊ฒ์ฆ
- ์ ์ง์ ์ผ๋ก ์ ์ฒด ์ฌ์ฉ์๋ก ํธ๋ํฝ์ ํ์ฅ
- ์ฅ์ ๋ฐ์ ์ ์ํฅ์ ์ต์ํํ๊ณ ๋น ๋ฅด๊ฒ ๋ณต๊ตฌ ๊ฐ๋ฅ
์ฐ๋ฆฌ ์๋น์ค๋ ์ฝ๋ฉํ ์คํธ ํด์ค์ง์ ์ ๊ณตํ๋ ํ๋ซํผ์ผ๋ก, ๋งค์ผ ์ค์ 9์ 30๋ถ๋ถํฐ 10์๊น์ง๊ฐ ์ต๋ ํธ๋ํฝ ์๊ฐ๋์ด๋ฉฐ, ์ด๋ ์ต๋ ๋์ ์ ์์ ์๋ ์ฝ 150๋ช ์ผ๋ก ์์๋ฉ๋๋ค.
์ฌ์ฉ์๋ ์งง์ ์๊ฐ ์์ ๋ฌธ์ ํ์ด ๋ฐ ํด์ค์ ํ์ธํ๊ธฐ ๋๋ฌธ์, ์๊ฐ์ ์ธ ์ ์ ์ง์ฐ์ด๋ ์๋น์ค ์ค๋จ์ ์ฌ์ฉ์ ๊ฒฝํ์ ๋งค์ฐ ์น๋ช ์ ์ผ ์ ์์ต๋๋ค.
MVP ์ด๊ธฐ์๋ ์๋น์ค ์ ๋ขฐ์ฑ๊ณผ ๋ฌด์ค๋จ์ ์ต์ฐ์ ์ผ๋ก ํด์ผ ํ๋ฏ๋ก, ๊ฒ์ฆ ํ ํ ๋ฒ์ ์ ์ฒด ํธ๋ํฝ์ ์ ํํ๋ Blue-Green ๋ฐฐํฌ๋ฅผ ์ ์ฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋น ๋ฅธ ๋กค๋ฐฑ์ด ๊ฐ๋ฅํ๊ณ , ์๋น์ค ์ด๊ธฐ ํ์ง์ ์์ ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์๋น์ค๊ฐ ์ ์ฐจ ์์ ๋๊ณ ๊ธฐ๋ฅ ๊ฐ์ ๋ฐ ๋ฒ๊ทธ ์์ ์ด ์ฆ์์ง ๊ฒฝ์ฐ,
- ์ด์ ํ๊ฒฝ์ ๋ณ๊ฒฝ ์ฃผ๊ธฐ๊ฐ ์งง์์ง๊ณ , ๋ค์ํ ์ฝ๋ ๋ณ๊ฒฝ์ด ๋์ ๋๋ฉด์ ๋จ๋ฒ์ ์ ์ฒด ์ฌ์ฉ์์๊ฒ ๋ฐฐํฌํ ๊ฒฝ์ฐ, ์์์น ๋ชปํ ์ค๋ฅ๋ ์ฑ๋ฅ ์ ํ๊ฐ ์ ์ฒด ์ฌ์ฉ์์๊ฒ ์ฆ์ ์ํฅ์ ๋ฏธ์น ์ํ์ด ์ปค์ง๋๋ค.
- ํนํ, ๋ชจ๋ ์ฌ์ฉ์๊ฐ ๋์์ ์๋ก์ด ๋ฒ์ ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ์์์ ์ด์ ์งํ๋ง์ผ๋ก๋ ์๋น์ค ์ ์ฒด์ ์ฅ์ ๊ฐ ๋ฐ์ํ ์ ์์ด, ๋ณต๊ตฌ ์์ ๋ถ๋ด๊ณผ ์ฅ์ ๋ฆฌ์คํฌ๊ฐ ๊ธ๊ฒฉํ ์ฆ๊ฐํฉ๋๋ค.
๋ฐ๋ผ์ ์ผ๋ถ ์ฌ์ฉ์ ๊ทธ๋ฃน์๋ง ์ ๋ฒ์ ์ ๋ ธ์ถํ์ฌ ์์ ์ฑ์ ๊ฒ์ฆํ๊ณ , ๋ฌธ์ ๊ฐ ์์ ๋ ์ ์ง์ ์ผ๋ก ๋ฐฐํฌ๋ฅผ ํ์ฅํ๋ ์นด๋๋ฆฌ ๋ฐฐํฌ ์ ๋ต์ ํตํด ์ด์ ๋ฆฌ์คํฌ๋ฅผ ์ต์ํํ ํ์๊ฐ ์์ต๋๋ค.
๋ํ, ์ฐ๋ฆฌ ์๋น์ค๋ ๋งค์ผ ์๋ก์ด ๋ฌธ์ ์ ํด์ค ์ ๋ฐ์ดํธ๊ฐ ํ์ํ ๊ตฌ์กฐ์ด๊ธฐ ๋๋ฌธ์,
- ์ฝํ ์ธ ํน์ฑ์ ์ฌ์ฉ์์๊ฒ ๋งค์ผ ์๋ก์ด ๋ฌธ์ ๋ฅผ ์ ๊ณตํด์ผ ํ๋ฉฐ,
- ์ด์ ๋ฐ๋ผ ๋ฌธ์ ๋ฐ์ดํฐ, ํด์ค ๋ฐ์ดํฐ๋ฟ ์๋๋ผ ๊ด๋ จ ๊ธฐ๋ฅ(์ถ์ ๋ก์ง, ํด์ค ํ์ด์ง ๋ ๋๋ง ๋ฑ) ์ ๋ฐ์ดํธ๋ ๋น๋ฒํ๊ฒ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.
- ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฐฐํฌ ์ฃผ๊ธฐ๊ฐ ์งง์์ง๊ณ , ๋ฐฐํฌ ๋น๋ ๋ํ ์ ์ฐจ ์ฆ๊ฐํ ์๋ฐ์ ์์ต๋๋ค.
๋น๋ฒํ ๋ฐฐํฌ ํ๊ฒฝ์์๋, ๋๊ท๋ชจ ์ผ๊ด ๋ฐฐํฌ ๋ฐฉ์๋ณด๋ค๋ ์๊ท๋ชจ ๋ถ์ฐ ๋ฐฐํฌ๋ฅผ ํตํ ๋ฆฌ์คํฌ ํต์ ๊ฐ ํ์์ ์ด๊ธฐ ๋๋ฌธ์, ์นด๋๋ฆฌ ๋ฐฐํฌ ๋ฐฉ์์ด ์ ์ง์ ์ผ๋ก ํ์ํ๊ฒ ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก, ๊ธ์์ผ ์คํ 18์ ์ ๊ธฐ ๋ฐฐํฌ ์ดํ ๋น๊ต์ ์ฌ์ฉ์ ์ ์์ด ์ ์ ์ผ๊ฐ ์๊ฐ๋๋ฅผ ํ์ฉํ์ฌ ๋ชจ๋ํฐ๋ง ๋ฐ ์์ ์ฑ ํ๋ณด ์๊ฐ์ ๊ฐ์ง ์ ์์ด, ์ด์ ํจ์จ์ฑ ์ธก๋ฉด์์๋ ์ ๋ฆฌํฉ๋๋ค.

์ด๋ฒ CD(Continuous Delivery/Deployment) ํ์ดํ๋ผ์ธ์ ์คํ
์ด์ง ์๋ํ ๋ฐฐํฌ โ ์ด์ ๋ฐฐํฌ ์น์ธ โ Blue-Green ๋๋ ์นด๋๋ฆฌ ๋ฐฐํฌ โ QA ๋ฐ ๋ชจ๋ํฐ๋ง โ ์ต์ข
ํ์ ๊น์ง ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ตฌ์กฐ๋ก ์ค๊ณ๋์์ต๋๋ค.
ํนํ, Blue-Green ๋ฐฐํฌ์ ์นด๋๋ฆฌ ๋ฐฐํฌ๋ฅผ ์ ์ฉํ๋ , ์๋ ๋ฐฐํฌ๋ฅผ ์งํํ๋ ๊ด๊ณ์์ด, Slack ์๋ฆผ ๋ฐ์ก, ์ด์ QA ์ ๊ฒ, ์ด๊ธฐ ์ง์ค ๋ชจ๋ํฐ๋ง ๋ฑ์ ์ด์ ํ๋ฆ์ ๋์ผํ๊ฒ ํ์ ์ ์ฐจ๋ก ํฌํจ๋์ด์ผ ํฉ๋๋ค. ์๋ ๋ฐฐํฌ ํ๊ฒฝ์์๋ ์ด๋ฌํ ์ด์ ํ๋ก์ธ์ค๋ฅผ ์๊ฒฉํ ์ค์ํ์ฌ ์๋น์ค ์์ ์ฑ๊ณผ ๋ฐฐํฌ ์ ๋ขฐ์ฑ์ ํ๋ณดํฉ๋๋ค.
- Push release tag
- Build artifact
- ์คํ ์ด์ง ์๋ ๋ฐฐํฌ
- ์คํ ์ด์ง ์๋ํ ํ ์คํธ
- ์ฑ๊ณต ์: ์ด์ ๋ฐฐํฌ ์น์ธ ์์ฒญ, ์ด์ ๋ฐฐํฌ ์น์ธ
- ์คํจ ์: ๋ฐฐํฌ ์ฐจ๋จ ๋ฐ Slack ์๋ฆผ
- Blue ๋ฒ์ ๋ฐฐํฌ
- Health Check ์ฑ๊ณต ์ ํธ๋ํฝ ์ ํ (Green โ Blue)
- ๋ฐฐํฌ ์๋ฃ ํ QA ๊ฒ์ฆ ๋ฐ ์ด๊ธฐ ์ง์ค ๋ชจ๋ํฐ๋ง
- ์ด์ ๋ฐ์ ์ Green์ผ๋ก ๋กค๋ฐฑ
- 5~10% ์นด๋๋ฆฌ ๋ฐฐํฌ
- ๋ชจ๋ํฐ๋ง ํ ์ ์ง์ ํธ๋ํฝ ํ์ฅ (10%โ30%โ70%โ100%)
- ์ด์ ๋ฐ์ ์ ์นด๋๋ฆฌ ๋กค๋ฐฑ
- Health Check ์คํจ ์ ๋ฐฐํฌ ์ค๋จ ๋ฐ ๋กค๋ฐฑ
- ์ด๊ธฐ ๋ชจ๋ํฐ๋ง ์ค ์ด์ ๋ฐ์ ์ ๊ธด๊ธ ๋กค๋ฐฑ ๋๋ ํซํฝ์ค
- ์คํ ์ด์ง ํ ์คํธ ์คํจ ์ ์๋ฆผ
- ์ด์ ๋ฐฐํฌ ์น์ธ ์์ฒญ ์๋ฆผ
- ๋ฐฐํฌ ์์, ์๋ฃ, ์ด์ ๋ฐ์, ๋กค๋ฐฑ ๋ฑ ์ํ๋ณ ์๋ฆผ
๋จ๊ณ | Blue-Green | ์นด๋๋ฆฌ ๋ฐฐํฌ |
---|---|---|
์ด๊ธฐ ๋ฐฐํฌ ๋ฐฉ์ | ์ ์ฒด ํธ๋ํฝ ํ ๋ฒ์ ์ ํ | ์์ ํธ๋ํฝ๋ถํฐ ์ ์ง์ ์ ํ |
์ฅ์ ๋์ | Green์ผ๋ก ์ ์ฒด ๋ณต๊ท | ์นด๋๋ฆฌ ํธ๋ํฝ๋ง ๋กค๋ฐฑ |
๋ฆฌ์คํฌ ๊ด๋ฆฌ | ๋น ๋ฅธ ๋กค๋ฐฑ ๊ฐ๋ฅ | ์ ์ง์ ํ์ฅ์ผ๋ก ๋ฆฌ์คํฌ ์ต์ํ |
์ ์ฉ ์์ | MVP ๋ฐฐํฌ ์ดํ ์ ์ฉ | ์๋น์ค ๊ณ ๋ํ ์ดํ ์ ์ฉ |
ํค์๋: ์คํ ์ด์ง ์๋ํ โ ์ด์ ์น์ธ โ Blue-Green/์นด๋๋ฆฌ ๋ฐฐํฌ โ QA โ ๋ชจ๋ํฐ๋ง โ ํ์ or ๋กค๋ฐฑ ๋์
- ์คํ ์ด์ง ์๋ํ ํ ์คํธ ์คํจ ์: Slack ์๋ฆผ ๋ฐ์ก
- ์คํ ์ด์ง ํ ์คํธ ์ฑ๊ณต ์: ์ด์ ๋ฐฐํฌ ์น์ธ ์์ฒญ Slack ์๋ฆผ
- ์ด์ ๋ฐฐํฌ ์์ ์: Slack ์๋ฆผ ๋ฐ์ก
- ์ด์ ๋ฐฐํฌ ์ฑ๊ณต ์: Slack ์๋ฆผ ๋ฐ์ก
- ํฌ์ค์ฒดํฌ ์คํจ/๊ธด๊ธ ๋กค๋ฐฑ ๋ฐ์ ์: ๊ธด๊ธ ๋กค๋ฐฑ Slack ์๋ฆผ
- ์ต์ข QA ์๋ฃ ํ ๋ฐฐํฌ ํ์ : Slack ์๋ฆผ ๋ฐ์ก
- Slack Incoming Webhook์ ์์ฑํ์ฌ GitHub Secrets์
SLACK_WEBHOOK_URL
๋ก ์ ์ฅ
- name: Slack ์๋ฆผ - ์คํ
์ด์ง ํ
์คํธ ์คํจ
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"โ ๏ธ [์คํ
์ด์ง ํ
์คํธ ์คํจ] - ๋ฐฐํฌ๊ฐ ์ฐจ๋จ๋์์ต๋๋ค."}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Slack ์๋ฆผ - ์ด์ ๋ฐฐํฌ ์น์ธ ์์ฒญ
if: success()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"๐ [์คํ
์ด์ง ํ
์คํธ ์ฑ๊ณต] ์ด์ ๋ฐฐํฌ ์น์ธ ์์ฒญ์ ํด์ฃผ์ธ์."}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Slack ์๋ฆผ - ์ด์ ๋ฐฐํฌ ์์
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"๐ [์ด์ ๋ฐฐํฌ ์์] ๋ฐฐํฌ๋ฅผ ์์ํฉ๋๋ค."}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Slack ์๋ฆผ - ์ด์ ๋ฐฐํฌ ์๋ฃ
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"๐ [์ด์ ๋ฐฐํฌ ์๋ฃ] QA๋ฅผ ์์ํด์ฃผ์ธ์."}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Slack ์๋ฆผ - ํฌ์ค์ฒดํฌ ์คํจ ๋ฐ ๋กค๋ฐฑ
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"๐ฅ [์ด์ ํฌ์ค์ฒดํฌ ์คํจ] ๊ธด๊ธ ๋กค๋ฐฑ์ ์ํํฉ๋๋ค!"}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Slack ์๋ฆผ - ์ต์ข
๋ฐฐํฌ ํ์
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"โ
[์ด์ ๋ฐฐํฌ ํ์ ] ์๋น์ค๊ฐ ์ ์ ์ด์ ์ค์
๋๋ค."}' \
${{ secrets.SLACK_WEBHOOK_URL }}
โ ๏ธ ๊ฒฝ๊ณ (ํ ์คํธ ์คํจ)- ๐ ์์ (๋ฐฐํฌ ์์)
- ๐ ์ฑ๊ณต (๋ฐฐํฌ ์๋ฃ)
- ๐ฅ ๊ธด๊ธ (๋กค๋ฐฑ)
- โ ์ต์ข ์๋ฃ (QA ํ์ )
ํญ๋ชฉ ๋ฒํธ | ์ฒดํฌ ํญ๋ชฉ | ํ์ธ ์ฌ๋ถ |
---|---|---|
1 | ๋ฉ์ธ ํ์ด์ง ์ ์ ์ ์ ์ฌ๋ถ | โ / โ |
2 | ๋ก๊ทธ์ธ/ํ์๊ฐ์ ์ ์ ์๋ ์ฌ๋ถ | โ / โ |
3 | ์ค๋์ ๋ฌธ์ ๋ฆฌ์คํธ ์ ์ ํ์ ์ฌ๋ถ | โ / โ |
4 | ๋ฌธ์ ์์ธ ํ์ด์ง ์ ์ ์กฐํ ์ฌ๋ถ | โ / โ |
5 | ํด์ค ํ์ด์ง ์ ์ ์กฐํ ์ฌ๋ถ | โ / โ |
6 | ์ฃผ์ ๋ฒํผ(์ ์ถ, ํด์ค ํ์ธ ๋ฑ) ์ ์ ๋์ ์ฌ๋ถ | โ / โ |
7 | ์๋ฌ ํ์ด์ง(404, 500) ๋ฐ์ ์ฌ๋ถ | โ / โ |
8 | ์๋ต ์๋ ์ง์ฐ ์ฌ๋ถ ํ์ธ (API ํธ์ถ) | โ / โ |
9 | ๋ฐฐํฌ ํ ์ ๊ท ์๋ฌ ๋ก๊ทธ ์ ์ ์ฌ๋ถ | โ / โ |
10 | ๊ธฐํ ์ด์ ํ์ ๋ฐ์ ์ฌ๋ถ | โ / โ |
ํญ๋ชฉ | ์ญํ ์ค๋ช | ๋ด๋น์ |
---|---|---|
๋ฐฐํฌ ์น์ธ์ | ์ต์ข ๋ฐฐํฌ ์น์ธ | evan.kim |
๋ชจ๋ํฐ๋ง ๋ด๋น์ | ๋ฐฐํฌ ์งํ ์์คํ ์ํ ๋ชจ๋ํฐ๋ง | noah.hwang, sophie.kim |
๋กค๋ฐฑ ๋ด๋น์ | ์ฅ์ ๋ฐ์ ์ ์ฆ์ ๋กค๋ฐฑ | evan.kim, noah.hwang |
๊ธด๊ธ ํซํฝ์ค ๋ด๋น์ | ๋น ๋ฅธ ์์ ๋ฐ ์ฌ๋ฐฐํฌ ๋ด๋น | noah.hwang |
์ฌ์ฉ์ ๋ฌธ์ ๋์ ๋ด๋น์ (CS) | ์ฌ์ฉ์ ๋ฌธ์ ๋์ | sophie.kim |
๋ฆฌํฌํธ ์ ๋ฆฌ ๋ด๋น์ | ๋ฐฐํฌ/QA ๊ฒฐ๊ณผ ๊ธฐ๋ก ๋ฐ ๊ณต์ | sophie.kim |
Slack ์๋ฆผ ๋ด๋น์ | ๋ฐฐํฌ ์๋ฃ ๋ฑ ์๋ฆผ ๋ฐ์ก | evan.kim |
QA ์ฒดํฌ๋ฆฌ์คํธ ์์ฑ์ | ์ด์ QA ์ฒดํฌ๋ฆฌ์คํธ ์์ฑ ๋ฐ ์ ๊ฒ | noah.hwang |
- ๋ฐฐํฌ ๋์: AWS EC2 ์ธ์คํด์ค (Ubuntu, Amazon Linux2 ๋ฑ ์์)
- ๋ฐฉ์: GitHub Actions + SSH ๋ฐฐํฌ + systemd ์๋น์ค ์ฌ์์
- ํ ์คํธ ๋ฐ ๋ชจ๋ํฐ๋ง: Health Check ์คํฌ๋ฆฝํธ + Slack ์๋ฆผ
1. CI์ CD๋ฅผ ํ๋์ ํ๋ซํผ์์ ํตํฉ ๊ด๋ฆฌ ๊ฐ๋ฅ
- ์ด๋ฏธ CI ํ์ดํ๋ผ์ธ์ GitHub Actions๋ก ๊ตฌ์ฑํ๊ณ ์๊ธฐ ๋๋ฌธ์, ๋ณ๋์ ๋๊ตฌ ์์ด CD๊น์ง GitHub Actions ๋ด์์ ์ด์ด์ ๊ตฌ์ฑ ๊ฐ๋ฅ
- ๋น๋, ํ ์คํธ, ๋ฐฐํฌ๊น์ง ์ ์ฒด DevOps ํ๋ฆ์ ํ๋์ ์ํฌํ๋ก์ฐ ํ์ผ๋ก ๊ด๋ฆฌ ๊ฐ๋ฅ
2. GitHub ์ ์ฅ์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์๋ํ์ ์ต์ ํ
-
release-*
ํ๊ทธ ํธ์ ๋ฑ GitHub ๋ด ์ด๋ฒคํธ(trigger)์ ๋งค์ฐ ์ฝ๊ฒ ์ฐ๋ ๊ฐ๋ฅ -
push
,pull_request
,tag
,schedule
๋ฑ ๋ค์ํ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๋ฐฐํฌ ์๋ํ ๊ตฌ์ฑ์ด ๊ฐ๋จ
3. ํ์ต ๋ฐ ์ ์ง๋ณด์๊ฐ ๊ฐ๋จํจ
- ๋ค๋ฅธ CD ๋๊ตฌ(Jenkins, ArgoCD ๋ฑ)์ ๋นํด ์ค์ ์ด ์ง๊ด์ ์ด๊ณ ,
YAML
๊ธฐ๋ฐ์ผ๋ก ์ฝ๊ฒ ์ดํด ๊ฐ๋ฅ - ์์ ํ์ด๋ MVP ๋จ๊ณ์์ ๋์ ์ฅ๋ฒฝ์ด ๋ฎ๊ณ , ์ ์ง๋ณด์๊ฐ ์ฌ์
4. ์ธ๋ถ ๋๊ตฌ ์ค์น ์์ด ๋ฐ๋ก ์คํ ๊ฐ๋ฅ
- GitHub Actions๋ GitHub ํ๊ฒฝ ๋ด์์ ๋ฐ๋ก ์คํ๋๋ฏ๋ก, Jenkins์ฒ๋ผ ๋ณ๋ ์๋ฒ ๊ตฌ์ฑ ์์ด๋ ์ด์ ๊ฐ๋ฅ
- AWS EC2๋ฐฐํฌ ์์๋
scp
,ssh
์ก์ ์ ํตํด ๊ฐ๋จํ๊ฒ ๋ฐฐํฌ ์๋ํ ๊ตฌํ ๊ฐ๋ฅ
5. ๋น์ฉ ํจ์จ์ฑ๊ณผ GitHub ์ฐ๋์ฑ
- GitHub Actions๋ ๊ฐ์ธ ๋๋ ์๊ท๋ชจ ํ๋ก์ ํธ์ ๋ํด ๋ฌด๋ฃ ์๊ธ์ ๋ก๋ ์ถฉ๋ถํ ์ฌ์ฉ ๊ฐ๋ฅ
- GitHub์์ ์ํฌ๋ฆฟ ๊ด๋ฆฌ, ๋ฒ์ ์ปจํธ๋กค, PR ์ฐ๋ ๋ฑ ํตํฉ์ฑ์ด ๋ฐ์ด๋จ
๋จ๊ณ | ์ค๋ช |
---|---|
ํธ๋ฆฌ๊ฑฐ | main ๋ธ๋์น์ ํ๊ทธ(release-*)๊ฐ push๋๋ฉด CD ์์ |
์ํฐํฉํธ ๋ค์ด๋ก๋ | CI์์ ์์ฑ๋ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ(.jar, React build/, FastAPI/) ๋ค์ด๋ก๋ |
์ ์ก | AWS EC2์ ftp๋ก ์ ๋ก๋ |
์ ๊ท ๋ฒ์ ๋ฐฐํฌ ์ค๋น | ์ ๋ฒ์ ๋๋ ํ ๋ฆฌ์ ๋ฐฐ์น, systemd ์๋น์ค ์ค๋น |
ํฌ์ค ์ฒดํฌ | FastAPI์ SpringBoot API /health ํธ์ถ ๊ฒฐ๊ณผ ํ์ธ |
ํธ๋ํฝ ์ ํ (Nginx switch) | symlink ๋ณ๊ฒฝ ๋๋ Nginx config ์ค์ ํ reload |
๋ชจ๋ํฐ๋ง | 10๋ถ๊ฐ ์๋ต ๋ชจ๋ํฐ๋ง ํ ๋ฌธ์ ์์ผ๋ฉด green ๋ฒ์ ์ ๊ฑฐ |
์คํจ ์ ๋กค๋ฐฑ | symlink ์ด์ ๋ฒ์ ์ผ๋ก ๋ณต์ + ์๋น์ค ์ฌ์์ |
- systemd service์
ExecStartPre
๋ก ํฌ์ค ์ฒดํฌ ํ ์คํ - ์คํจ ์ ๋์ค์ฝ๋ ์๋ฆผ โ ๊ธฐ์กด ๋๋ ํ ๋ฆฌ๋ก symlink ๋ณต๊ตฌ โ ์ฌ์์
on:
push:
tags:
- 'release-*'
-
release-
๋ก ์์ํ๋ ํ๊ทธ(ex.release-v1.0
)๋ฅผ ํธ์ํ๋ฉด ์๋์ผ๋ก CD ํ์ดํ๋ผ์ธ์ด ์คํ๋ผ์ AWS ์๋ฒ์ ๋ฐฐํฌ๊ฐ ์งํ
- name: Download React Build Artifact
uses: actions/download-artifact@v3
with:
name: react-build
-
name: Deploy React via SSH
uses: appleboy/[email protected]
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
source: "frontend/build/"
target: "/home/ubuntu/deployments/react-build/"
-
name: Replace Nginx Static Files
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
script: |
sudo rm -rf /var/www/html/*
sudo cp -r /home/ubuntu/deployments/react-build/* /var/www/html/
sudo systemctl reload nginx
- name: Download Build Artifact
uses: actions/download-artifact@v3
with:
name: springboot-jar
-
name: Deploy via SSH
uses: appleboy/[email protected]
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
source: "build/libs/myapp.jar"
target: "/home/ubuntu/deployments/myapp-blue.jar"
-
name: Run Remote Deploy Script
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
script: |
sudo systemctl stop spring.service
sudo cp /home/ubuntu/deployments/myapp-blue.jar /opt/myapp/app.jar
sudo systemctl start spring.service
- name: Download FastAPI Artifact
uses: actions/download-artifact@v3
with:
name: fastapi-src
-
name: Deploy FastAPI via SSH
uses: appleboy/[email protected]
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
source: "fastapi/"
target: "/home/ubuntu/deployments/fastapi-blue/"
-
name: Run FastAPI Deploy Script
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.AWS_HOST }}
username: ubuntu
key: ${{ secrets.AWS_SSH_KEY }}
script: |
sudo systemctl stop fastapi.service
sudo rm -rf /opt/fastapi/*
sudo cp -r /home/ubuntu/deployments/fastapi-blue/* /opt/fastapi/
sudo systemctl start fastapi.service
// ์ ํ๋ฆฌ์ผ์ด์
ํฌํธ (๊ธฐ๋ณธ: 8080)
PORT=8080
// ํฌ์ค์ฒดํฌ ์์ฒญ
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$RESPONSE" -eq 200 ]; then
echo "โ
Spring Boot ์ ํ๋ฆฌ์ผ์ด์
์ด ์ ์์ ์ผ๋ก ์คํ ์ค์
๋๋ค."
exit 0
else
echo "โ ํฌ์ค์ฒดํฌ ์คํจ: ์ํ ์ฝ๋ $RESPONSE"
exit 1
fi
PORT=8000
ENDPOINT="/health"
URL="<http://localhost>:$PORT$ENDPOINT"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$RESPONSE" -eq 200 ]; then
echo "โ
FastAPI ํฌ์ค์ฒดํฌ ์ฑ๊ณต (HTTP 200)"
exit 0
else
echo "โ FastAPI ํฌ์ค์ฒดํฌ ์คํจ: ์ํ ์ฝ๋ $RESPONSE"
exit 1
fi
# ์ฌ๋ณผ๋ฆญ ๋งํฌ ๊ต์ฒด ๋ฐฉ์
ln -sfn /var/www/app-blue /var/www/html
sudo systemctl reload nginx
- GitHub Secrets ์ฌ์ฉ:
AWS_HOST
AWS_SSH_KEY
- ์๋น์ค ๋ด๋ถ ํ๊ฒฝ๋ณ์๋
.env
ํ์ผ์ด ์๋ systemd ํ๊ฒฝ ์ค์ ํ์ผ๋ก ๊ด๋ฆฌ