์๋น์ค์ ๊ท๋ชจ๊ฐ ๋ณต์กํด์ง๊ณ ์ปค์ง์๋ก, ์๋น์ค๋ฅผ ๋ฐฐํฌํ๋ ๊ณผ์ ์ด ๋ณต์กํด์ง๊ณ ์์๋๋ ์๊ฐ์ด ๋์ด๋๊ฒ ๋๋ค.
๋ํ ๋ณ๊ฒฝ ์ฌํญ์ด ์๊ธธ ๋๋ง๋ค ๋ฐฐํฌ ๊ณผ์ ์ ๋งค๋ฒ ์๋์ผ๋ก ์งํํ๋ค๋ฉด, ๋ฐฐํฌ ๊ณผ์ ์ ๋ง์ ์๊ฐ์ ํ๋นํด์ผ ํ ๊ฒ์ด๋ค.
๋ฒํผ ํ๋๋ง ํด๋ฆญํ๋ฉด ์ ์ฒด ๋ฐฐํฌ ๊ณผ์ ์ด '์๋'์ผ๋ก ์งํ๋๊ฒ ๋ง๋ค ์๋ ์์๊น?
์ด๋ฒ ์ ๋์์๋ ๋ฐฐํฌ ์๋ํ ๊ฐ๋ ์ ๋ํด ํ์ตํ๊ณ , ์ค์ต์ ํตํด ๋ฐฐํฌ ์๋ํ์ ์ฅ์ ์ ์ฒดํํด๋ณด๊ฒ ๋ค.
CI/CD๋ ์ฝ์ด๋ก, ๋ช ๊ฐ์ง์ ๋ค๋ฅธ ์๋ฏธ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
CI/CD์ "CI"๋ ๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ํ ํ๋ก์ธ์ค์ธ ์ง์์ ์ธ ํตํฉ(Continuous Integration)์ ์๋ฏธํ๋ค.
CI๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๊ตฌํํ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ํ ์๋ก์ด ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ๊ธฐ์ ์ผ๋ก ๋น๋ ๋ฐ ํ
์คํธ๋์ด ๊ณต์ ๋ฆฌํฌ์งํ ๋ฆฌ์ ํตํฉ๋๋ฏ๋ก ์ฌ๋ฌ ๋ช
์ ๊ฐ๋ฐ์๊ฐ ๋์์ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ๊ณผ ๊ด๋ จ๋ ์ฝ๋ ์์
์ ํ ๊ฒฝ์ฐ ์๋ก ์ถฉ๋ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
CI/CD์ "CD"๋ ์ง์์ ์ธ ์๋น์ค ์ ๊ณต(Continuous Delivery) ๋ฐ/๋๋ ์ง์์ ์ธ ๋ฐฐํฌ(Continuous Deployment)๋ฅผ ์๋ฏธํ๋ฉฐ ์ด ๋ ์ฉ์ด๋ ์ํธ ๊ตํ์ ์ผ๋ก ์ฌ์ฉ๋๋ค. ๋ ๊ฐ์ง ์๋ฏธ ๋ชจ๋ ํ์ดํ๋ผ์ธ์ ์ถ๊ฐ ๋จ๊ณ์ ๋ํ ์๋ํ๋ฅผ ๋ปํ์ง๋ง ๋๋ก๋ ์ผ๋ง๋ ๋ง์ ์๋ํ๊ฐ ์ด๋ฃจ์ด์ง๊ณ ์๋์ง๋ฅผ ์ค๋ช ํ๊ธฐ ์ํด ๋ณ๋๋ก ์ฌ์ฉ๋๊ธฐ๋ ํ๋ค.
๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ํ ํ๋ก์ธ์ค๋ผ๊ณ ๋ณผ ์ ์์ผ๋ฉฐ, Code - Build - Test ๋จ๊ณ์์ ๊พํ ์ ์๋ค.
์ด ๊ณผ์ ์์ ๊ฐ๋ฐ์๋ ์ฝ๋๋ฅผ ์ฆ๊ฒ ์๊ฒฉ ์ฝ๋ ์ ์ฅ์์ pushํ๊ณ , ํ ์คํธ ๋ฐ ๋น๋๋ฅผ ํ๋ฉฐ ๋น๋ ๊ฒฐ๊ณผ๋ฅผ ํตํด ๋น๋๊ฐ ์ฑ๊ณตํ๋์ง ์คํจํ๋์ง ํ์ธ์ ํ๊ณ , ํตํฉ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ํตํด ๊ฐ์ ๋ฐฉ์์ ์ฐพ๋๋ค. ์ด ์ง์์ ์ธ ํตํฉ ๊ณผ์ ์ ํตํด ๊ฐ๋ฐ์๋ ๋ฒ๊ทธ๋ฅผ ์ผ์ฐ ๋ฐ๊ฒฌํ ์ ์๊ณ , ํ ์คํธ๊ฐ ์๋ฃ๋ ์ฝ๋์ ๋ํด ๋น ๋ฅธ ์ ๋ฌ์ด ๊ฐ๋ฅํด์ง๋ฉฐ ์ง์์ ์ธ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
์ง์์ ํตํฉ์ ๋ชจ๋ ์ฝ๋ ๋ณํ๋ฅผ ํ๋์ ๋ฆฌํฌ์งํ ๋ฆฌ์์ ๊ด๋ฆฌํ๋ ๊ฒ๋ถํฐ ์์ํ๋ค. ๋ชจ๋ ๊ฐ๋ฐํ์ด ์ฝ๋์ ๋ณํ๋ฅผ ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์, ํฌ๋ช ํ๊ฒ ๋ฌธ์ ์ ์ ํ์ ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ฆ์ ํ ๋ฆฌํ์คํธ(pull request)์ ๋จธ์ง(merge)๋ก ์ฝ๋๋ฅผ ์์ฃผ ํตํฉํ๋ค. ์ด๋, ๊ธฐ๋ณธ์ ์ธ ํ ์คํธ๋ ์๋์ํฌ ์ ์๋ค. ์ด๋ ๊ฒ ์ง์์ ํตํฉ์ ํตํด ๊ฐ๋ฐํ์ ๊ฐ์ ๊ฐ๋ฐํ ์ฝ๋๋ฅผ ์ด๋ฅธ ์์ ์ ์์ฃผ ํฉ์น๊ณ ์์ฃผ ํ ์คํธ ํด๋ณผ ์ ์๋ค.
์ง์์ ํตํฉ์ผ๋ก ๋ณด์ ์ด์, ์๋ฌ ๋ฑ์ ์ฝ๊ฒ ํ์ ํ ์ ์์ด ํด๋น ์ด์๋ฅผ ๋น ๋ฅด๊ฒ ๊ฐ์ ํ ์ ์๋ค. ์ด์ ์๋ ๊ฐ์ ๊ฐ๋ฐ์๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ํฉ์น๊ณ ๋ ํ, ๋ชจ๋ ๋ชจ์ฌ์ ๋น๋๋ฅผ ์์ํ๊ณ ๋์์ผ ๋ฌธ์ ์ ์ ํ์ ํ ์ ์์๋ค. ์ง์์ ํตํฉ์ด ์ ์ฉ๋ ๊ฐ๋ฐํ์ ์ฝ๋๋ฅผ ๋จธ์งํ๊ธฐ ์ , ์ด๋ฏธ ๋น๋ ์ค๋ฅ๋ ํ ์คํธ ์ค๋ฅ๋ฅผ ํ์ธํ์ฌ ํจ์ฌ ๋ ํจ์จ์ ์ธ ๊ฐ๋ฐ์ ํ ์ ์๊ฒ ๋๋ค.
์ง์์ ์ธ ์๋น์ค ์ ๊ณต(Continuous Delivery) ๋ฐ ์ง์์ ์ธ ๋ฐฐํฌ(Continuous Deployment)๋ฅผ ์๋ฏธํ๋ฉฐ
์ด ๋ ์ฉ์ด๋ ์ํธ ๊ตํ์ ์ผ๋ก ์ฌ์ฉ๋๋ค. ์ด ๋ถ๋ถ์ Release - Deploy - Operate ๋จ๊ณ์์ ๊พํ ์ ์๋ค.
์ง์์ ๋ฐฐํฌ์ ๊ฒฝ์ฐ, ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ณํฉ๋ถํฐ ํ๋ก๋์
์ ์ ํฉํ ๋น๋ ์ ๊ณต์
์ด๋ฅด๋ ๋ชจ๋ ๋จ๊ณ๋ก, ํ
์คํธ ์๋ํ์ ์ฝ๋ ๋ฐฐํฌ ์๋ํ๊ฐ ํฌํจ๋๋ค.
์ด ํ๋ก์ธ์ค๋ฅผ ์๋ฃํ๋ฉด ํ๋ก๋์
์ค๋น๊ฐ ์๋ฃ๋ ๋น๋๋ฅผ ์ฝ๋ ๋ฆฌํฌ์งํ ๋ฆฌ์ ์๋์ผ๋ก ๋ฐฐํฌํ ์ ์๊ธฐ
๋๋ฌธ์ ์ด์ํ์ด ๋ณด๋ค ๋น ๋ฅด๊ณ ์์ฝ๊ฒ ์ ํ๋ฆฌ์ผ์ด์
์ ํ๋ก๋์
์ผ๋ก ๋ฐฐํฌํ ์ ์๊ฒ ๋๋ค.
์ต๊ทผ์๋ ํด๋ผ์ฐ๋ ๊ธฐ์ ๋ฐ์ ๊ณผ ๋ง๋ฌผ๋ ค ์ง์์ ํตํฉ๊ณผ ์ง์์ ๋ฐฐํฌ๊ฐ ๋น ๋ฅธ ์๋๋ก ์งํ๋๋ฉด์ CI/CD๋ฅผ ํ๋๋ก ๋ฌถ์ด์ ๋ค๋ฃจ๋ ๊ฒฝ์ฐ๊ฐ ์ ์ฐจ ์ฆ๊ฐํ๊ณ ์๋ค. ์๋ฅผ ๋ค์ด, ์ด์ ์๋ ๋ฐฐํฌ ์์ฒด๊ฐ ์๋นํ ์ค๋ ๊ฑธ๋ฆฌ๊ณ ํ๋ ์ผ์ด์ด์ ๋ฐฐํฌ ์ด์ ๋จ๊ณ์์ ๋ง์ ๊ณ ๋ฏผ์ ํ๊ณค ํ๋ค. ์๋ฒ๋ฅผ ์ ๋ถ ์ฌ์์ํด์ผ ํ๋ค๊ฑฐ๋, ์ผ๋ถ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ๋ ๋ง์๊ธฐ ๋๋ฌธ์ด๋ค. ์์ฆ์ ๊ณ ๊ฐ์ ํผ๋๋ฐฑ์ ๋นจ๋ฆฌ ๋ฐ๊ธฐ ์ํด์๋ผ๋, ์๋น์ค๋ฅผ ์ค๋จํ์ง ์๊ธฐ ์ํด์๋ผ๋ ๋ฆด๋ฆฌ์ค๋ง ์ ๊ธฐ๋กํด ๋๊ณ ๋ฐ๋ก๋ฐ๋ก ๋ฐฐํฌํ๋ ์ฌ๋ก๊ฐ ์ฆ๊ฐํ๊ณ ์๋ค.
๋ฐฐํฌ ์๋ํ
๋ฐฐํฌ ์๋ํ๋ ํ ๋ฒ์ ํด๋ฆญ ํน์ ๋ช
๋ น์ด ์
๋ ฅ์ ํตํด ์ ์ฒด ๋ฐฐํฌ ๊ณผ์ ์ ์๋์ผ๋ก ์งํํ๋ ๊ฒ์ ๋ปํ๋ค.
๋ฐฐํฌ ์๋ํ๊ฐ ์ ํ์ํ ๊น?
๋ฐฐํฌ ์๋ํ๋ฅผ ํตํด ์ ์ฒด ๋ฐฐํฌ ๊ณผ์ ์ ๋งค๋ฒ ์ผ๊ด๋๊ฒ ์งํํ๋ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ์ฌ ํด๋จผ ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ์ฑ์ ๋ฎ์ถ ์ ์๋ค.
CI/CD ํ์ดํ๋ผ์ธ
์์ ์ฐ๋ฆฌ๋ ์ ํต์ ์ธ ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ๋ชจ๋ ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ๋ํด ๋ฐฐ์ ๋ค.
๊ทธ๋ฆฌ๊ณ SaaS๊ฐ ๋ชจ๋ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ก ๊ฐ๋ฐํ๊ธฐ ์ ํฉํ ์ํํธ์จ์ด์๋ ํ์ธํ๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ฒ์๋ ์ด๋ ๊ฒ ์๊ฐํด๋ณด์. ์ฌ์ฉ์ ์ ๋ฐ์ดํธ์ ๋ํ ๊ฑฑ์ ์์๋ ๋ฒ์ด๋ฌ๊ณ , ํ๋ฃจ์ ์ฌ๋ฌ ๋ฒ์ ๋ฐฐํฌ๋ ๊ฐ๋ฅํด์ก๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ๋น ๋ฅธ ๋ฐฐํฌ ์๋๋ฅผ ๋ณด์ฅ๋ฐ์ ์ ์์๊น? ๊ฐ๋ฐ์๊ฐ ๋ฐฐํฌํ ๋๋ง๋ค ์ผ์ผ์ด ๋น๋ํ๊ณ ๋ฐฐํฌํ๋ ์ด๋ฌํ ๊ณผ์ ์ด ์์์ด ์งํ๋๋ค๋ฉด ์ผ์ผ์ด ์ด ๊ณผ์ ์ ์ํํ๋ ๊ฒ์ด ๋ฒ์ก์ค๋ฝ๊ณ ์ง๋ฃจํ ๊ฒ์ด๋ค.
๊ทธ๋์ ์ด ์์์ด ์งํ๋๋ ๋ฐฐํฌ ๊ณผ์ ์ ์๋ํ์ํค๋ ๋ฐฉ๋ฒ์ ๊ตฌ์ถํ๊ฒ ๋๋๋ฐ, ๊ทธ๊ฒ์ CI/CD ํ์ดํ๋ผ์ธ์ด๋ผ๊ณ ํ๋ค.
ํด๋น ๊ทธ๋ฆผ์ ๋ฐฐํฌ ๊ณผ์ ์ ๋์ํํ ๊ฒ์ด๋ค.
๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์๊ฒฉ ์ ์ฅ์์ ์ฌ๋ฆฌ๋ฉด, ๊ทธ ์ฝ๋๊ฐ ๋น๋ ๋ฐ ํ ์คํธ์ ๋ฆด๋ฆฌ์ค๋ฅผ ๊ฑฐ์ณ ๋ฐฐํฌ ์๋ฒ๋ก ์ ๋ฌ๋๋ค.
๋ฐฐํฌ ์๋ฒ์ ๋๋ฌํ ๋น๋๋ ์ฝ๋๋ ์ ํ๋ฆฌ์ผ์ด์
์๋ฒ๋ก ์ต์ข
๋ฐฐํฌ๊ฐ ์๋ฃ๋๊ณ ,
๊ทธ ๊ฒฐ๊ณผ๋ฌผ์ ์ ์ ๊ฐ ์ง์ ํ์ธํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
์ฌ๊ธฐ์ ์๋ํ๋ฅผ ๊พํ๋ ๋ถ๋ถ์ ๋ณดํต ์ฝ๋๊ฐ ๋น๋๋๋ฉด์ ์ต์ข
์ ์ผ๋ก ๋ฐฐํฌ๊ฐ ๋๋ ๋จ๊ณ๊น์ง์ด๋ค.
์ด ๋ถ๋ถ์ ์ง์์ ์ธ ํตํฉ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ํ์ฌ ์ผ๋ จ์ ์๋ํ ๋จ๊ณ๋ก ๋ง๋๋๋ฐ, ์ด๊ฒ์ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋ค๊ณ ํํํ๋ค.
CI/CD ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ๋ ๊ธฐ๋ณธ ๋จ๊ณ์ ์ํ ์์
๋ฐฐํฌ์์ ํ์ดํ๋ผ์ธ(Pipeline)์ด๋ ์ฉ์ด๋ ์์ค ์ฝ๋์ ๊ด๋ฆฌ๋ถํฐ ์ค์ ์๋น์ค๋ก์ ๋ฐฐํฌ ๊ณผ์ ์ ์ฐ๊ฒฐํ๋ ๊ตฌ์กฐ๋ฅผ ๋ปํ๋ค.
ํ์ดํ๋ผ์ธ์ ์ ์ฒด ๋ฐฐํฌ ๊ณผ์ ์ ์ฌ๋ฌ ๋จ๊ณ(Stages)๋ก ์ธ ๊ฐ์ง ๋จ๊ณ๋ก ๋ถ๋ฆฌํ๋ค.
๊ฐ ๋จ๊ณ๋ ํ์ดํ๋ผ์ธ ์์์ ์์ฐจ์ ์ผ๋ก ์คํ๋๋ฉฐ, ๊ฐ ๋จ๊ณ๋ง๋ค ์ฃผ์ด์ง ์์
(Actions)๋ค์ ์ํํ๋ค.
ํ์ดํ๋ผ์ธ์ ๋จ๊ณ๋ ํ์์ ๋ฐ๋ผ ๋ ์ธ๋ถํ๋๊ฑฐ๋ ๊ฐ์ํ๋ ์ ์๋ค
DevOps๋ฅผ ์ ๋ฌธ์ผ๋ก ํ์ตํ๋ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด ํ์ดํ๋ผ์ธ์ ๋จ๊ณ๋ฅผ ์ธ๋ถํํด์ ๋๋๊ธฐ๋ ํ๋ค.
๋ํ, ํด๋น ํด์ ์๊ฐํ๋ ์
์ฒด์ ๋ฐ๋ผ ์ฉ์ด๋ฅผ ๋ฏธ๋ฌํ๊ฒ ๋ค๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ๋ ํ๋ค.
CI/CD ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ ์์ ๋ฐ ์ฅ์
๋ก์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ์ด ๊ณผ์ ์ด ์ค๋ฌด์์๋ ๋ฐ๋ณต์ ์ธ ํ๋ก์ธ์ค์ด๊ธฐ ๋๋ฌธ์
์ด ๋ถ๋ถ์ ์ผ๋ จ์ ์๋ํ ๋จ๊ณ๋ก ๋ง๋ ๋ค๊ณ ๋ณผ ์ ์๋ค.
์ด๋ ๊ฒ ๊ตฌ์ถ๋ ํ์ดํ๋ผ์ธ์ ์ต์ ๋ฒ์ ์ ์ํํธ์จ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฐ์ดํธํ๊ณ ์ ๊ณตํ๋ ค๋ ์ผ๋ จ์ ์ฒ๋ฆฌ ๋จ๊ณ์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ์๋์ผ๋ก ํ๋ ๊ฒ๋ณด๋ค ๋ ๋น ๋ฅด๊ณ ์์ ์ ์ด๋ฉฐ ํจ๊ณผ์ ์ผ๋ก ์ค์ฌ์ฃผ๊ณ CI/CD ์ธํ๋ผ์์ ํธํ์ฑ๊ณผ ํจ์จ์ฑ์ ๋์ฌ์ค๋ค.
GitHub Actions๋ Github๊ฐ ์ ๊ณตํ๋ ๋น๋, ํ ์คํธ ๋ฐ ๋ฐฐํฌ ํ์ดํ๋ผ์ธ์ ์๋ํํ ์ ์๋ CI/CD ํ๋ซํผ์ด๋ค.
๋ ํฌ์งํ ๋ฆฌ์์ Pull Request
๋ push
๊ฐ์ ์ด๋ฒคํธ๋ฅผ
ํธ๋ฆฌ๊ฑฐ๋ก GitHub ์์
์ํฌํ๋ก์ฐ(Workflow)๋ฅผ ๊ตฌ์ฑํ ์ ์๋ค.
์ํฌํ๋ก์ฐ๋ ํ๋ ์ด์์ ์์
์ด ์คํ๋๋ ์๋ํ ํ๋ก์ธ์ค๋ก,
๊ฐ ์์
์ ์์ฒด ๊ฐ์ ๋จธ์ ๋๋ ์ปจํ
์ด๋ ๋ด๋ถ์์ ์คํ๋๋ค.
์ํฌํ๋ก์ฐ๋ .yml
(ํน์ .yaml
) ํ์ผ์ ์ํด ๊ตฌ์ฑ๋๋ฉฐ, ํ
์คํธ, ๋ฐฐํฌ ๋ฑ ๊ธฐ๋ฅ์ ๋ฐ๋ผ ์ฌ๋ฌ ๊ฐ์
์ํฌํ๋ก์ฐ๋ก๋ ๋ง๋ค ์ ์๋ค. ์์ฑ๋ ์ํฌํ๋ก์ฐ๋ .github/workflows
๋๋ ํ ๋ฆฌ ์ดํ์ ์์นํ๋ค.
๋น๊ณต๊ฐ ๋ ํฌ์งํ ๋ฆฌ์ ๊ฒฝ์ฐ Github Actions๊ฐ ์๋ํ ๋์ ์ฉ๋๊ณผ ์๊ฐ์ด
์ ํ๋์ด ์์ผ๋ฉฐ ๊ณต๊ฐ ๋ ํฌ์งํ ๋ฆฌ๋ ๋ฌด๋ฃ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
์ด๋ฒ ํํ ๋ฆฌ์ผ์์๋ ๋๋ง์ ์๊ณ ๋ผ ์คํ ์ด์ธ ์๋ฒ ๋ ํผ๋ฐ์ค์ Github Action์ ์ด์ฉํ์ฌ ์งํํ๋ค.
๋จผ์ , ์์ ์ ๊นํ๋ธ ๊ณ์ ์ ์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ง๋ ๋ค.
๐ก public์ผ๋ก ๋ง๋ค์ด์ผ Github Action์ ๋ฌด๋ฃ๋ก ์ด์ฉํ ์ ์๋ค.
์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋๋ง์ ์๊ณ ๋ผ ์คํ ์ด์ธ ์๋ฒ ๋ ํผ๋ฐ์ค ์ฝ๋๋ฅผ pushํ๋ค.
drag & drop์ ํ ์๋ ์๊ฒ ์ง๋ง, ๊ฐ๋ฅํ๋ฉด ๊ธฐ์กด ๋๋ง์ ์๊ณ ๋ผ ์คํ
์ด์ธ ์๋ฒ ๋ ํผ๋ฐ์ค๋ฅผ
ํด๋ก ๋ฐ์์, ์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์๊ฒฉ ๋ฆฌํฌ์งํ ๋ฆฌ๋ก ๋ฑ๋กํ๊ณ , ์ฝ๋๋ฅผ pushํ๋ค.
# ๊ธฐ์กด ๋๋ง์ ์๊ณ ๋ผ ์คํ
์ด์ธ ์๋ฒ ๋ ํผ๋ฐ์ค ํด๋ก
git clone git@github.com:codestates-seb/fe-sprint-my-agora-states-server-reference.git
# ๋๋ ํฐ๋ฆฌ ์ด๋
cd fe-sprint-my-agora-states-server-reference
# ์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์๊ฒฉ ๋ฆฌํฌ์งํ ๋ฆฌ๋ก ๋ฑ๋ก
git remote add myRepo git@github.com:{์ฌ๋ฌ๋ถ์ ์์ด๋}/{์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ ์ด๋ฆ}.git
# ๊ธฐ์กด ๋ ํผ๋ฐ์ค ์ฝ๋๋ฅผ ์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ๋ก push
git push myRepo reference
์๋์ ๊ฐ์ด ์ฝ๋๊ฐ ๋ชจ๋ push๊ฐ ๋ ๋ชจ์ต์ ํ์ธํ๋ค. ์ปค๋ฐ ๊ธฐ๋ก์ ๋ณด์๋ฉด, ์ฃผํฉ์ ์์ ํ์ธํ ์ ์๋ค.
์ฃผํฉ์ ์์ด ๋ฌด์์ธ์ง ์ข ๋ ์์ธํ ํ์
ํ๊ธฐ ์ํด Actions ํญ์ผ๋ก ์ด๋ํ๋ค.
Github Action์ ์ฝ๋๋ฅผ ์ค์ ํด ๋๋ฉด ์ด๋ ๊ฒ ์๋ฒ ํ
์คํธ๊ฐ ์๋์ผ๋ก ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Github Action์ Github์ ํน์ ์ด๋ฒคํธ์ ๋ง๊ฒ ๋ค์ํ ์์
์ ์ํฌ ์ ์๋ CI/CD ํ๋ซํผ์ด๋ค. EC2์ ๊ฐ์ ํ๋์ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์คํ์์ผ์ ์ํ๋ ์์
์ ์ํฌ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ, ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ pushํ๊ธฐ๋ง ํ๋๋ฐ, ์ ์๋ํ์๊น? ./.github/workflows/pullRequest.yml
ํ์ผ์ ์ฝ์ด๋ณด๋ฉด, ์ธ์ ์ด๋ค job์ ํ ์ง ๋ช
์๋์ด ์๋ค.
npm install
์ ๋น๋๋ฅผ ์ํ ์ค๋น๊ณผ์ ์ผ๋ก ๋ณผ ์ ์๋ค. Node.js๋ก ๋ง๋ ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์
์npm test
๋ ์ ๋ ํ
์คํธ ๊ณผ์ ์ด๋ค. ์์ฑํ ์ฝ๋๊ฐ ์๊ตฌ์ฌํญname: Bare Minimum Requirements
# ์ธ์ job์ ์๋์ํฌ์ง
on: [push, pull_request]
# ์ด๋ค job์ ํ ์ง
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Bare Minimum Requirements
uses: actions/setup-node@v1
with:
node-version: '16'
- run: npm install
- run: npm test
Yet Another Markup Language์ ์ฝ์๋ก, ์ฌ๋์ด ์ฝ์ ์ ์๋ ๋ฐ์ดํฐ ์ง๋ ฌํ ์ธ์ด๋ฅผ ์๋ฏธํ๋ค.
ํ์ผ๋ก ์์ฑ ์ ํ์ฅ์๋ .yaml ํน์ .yml ํ์ฅ์๋ฅผ ๊ฐ์ง๋ค.
YAML์ ์ฌ๋์ด ์ฝ์ ์ ์๊ณ ์ดํดํ๊ธฐ ์ฌ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ์ค์์๋ ์ธ๊ธฐ๊ฐ ๋๋ค. ๋ํ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์
ํจ๊ป ์ฌ์ฉํ ์๋ ์๋ค. YAML์ ๊ทธ ์ ์ฐ์ฑ๊ณผ ์ ๊ทผ์ฑ์ผ๋ก ์ธํด ์๋ํ ํ๋ก์ธ์ค๋ฅผ ์์ฑํ๋ ๋ฐ์๋ ์ฌ์ฉ๋๋ค.
// YAML ํ์ผ
name: Bare Minimum Requirements
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Bare Minimum Requirements
uses: actions/setup-node@v1
with:
node-version: '16'
- run: npm install
- run: npm test
// JSON ํ์ผ
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
}
]
}
JSON ํ์ผ๊ณผ YAML ํ์ผ์ key-value ํํ๋ก ์์ฑ๋ ํ์ผ์ด๋ฉฐ, ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ ๊ฒ์๋ ๋์ผํ๋ค.
๊ทธ๋ฌ๋ YAML ํ์ผ์ "" (ํฐ๋ฐ์ดํ, double quotation marks) ์์ด ๋ฌธ์์ด ์์ฑ์ด ๊ฐ๋ฅํด, ์ค์ ์ ์ํ ์คํ์ด๋ ํ๋กํผํฐ ๊ฐ ๋ฑ์ด JSON ํ์ผ์ ๋นํด ํ๋์ ๋ค์ด์จ๋ค๋ ์ ์ด๋ค. ๋ํ JSON ํ์ผ์ฒ๋ผ {}
ํํ๋ก ๊ฐ์ธ์ค ํ์๋ ์๊ธฐ ๋๋ฌธ์ ์ค์ฝํ์ ์๋ฐ(์๋ชป ์ฐ๋ฉด ์ผ์ผ์ด ์ด๋๊ฐ ์ฒ์์ด๊ณ ๋์ธ์ง ์ฐพ์์ผ ํ๋ ๋ฑ)์์ ๋ฒ์ด๋ ์๋ ์๋ค.
๊ฒ๋ค๊ฐ YAML ํ์ผ์ JSON ํ์ผ๊ณผ ๋ค๋ฅด๊ฒ ์ฃผ์์ ์์ฑํ ์ ์๋ค๋ ์ ๋ ๊ต์ฅํ ์ด์ ์ผ๋ก ์์ฉํ๋ค.
JSON ํ์ผ์ ์ฃผ์์ ์์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ ํด๋น ํ์ผ ํ๋๋ง ๋๊ณ ์ปค๋ฎค๋์ผ์ด์
ํ๊ธฐ๊ฐ ๊น๋ค๋กญ์ง๋ง,
YAML ํ์ผ์ ์ ์ด์ ํ์ผ ๋ด์ ์ฃผ์์ ์์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ ์ปค๋ฎค๋์ผ์ด์
ํ๊ธฐ๊ฐ ํจ์ฌ ์์ํ๋ค.
๊ทธ๋ฆฌ๊ณ YAML์ JSON์ ์์ ํธํ ๊ฒฉ์ด๋ฏ๋ก, ๊ธฐ์กด json๋ฌธ์๋ฅผ ๊ทธ๋๋ก yamlํ์ผ๋ก ์ฌ์ฉํ๊ฑฐ๋ ์ํ๋
๋ถ๋ถ๋ง ์๋ณผ ์ ์๋ค. ๋ฐ๋๋ก yaml์ json์ผ๋ก ๋ณํํด ์ฌ์ฉํ ์๋ ์๋ค๋ ์ ์ด ์ฅ์ ์ผ๋ก ์์ฉํ๋ค.
YAML๋ ์ผ์ข
์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ด๊ธฐ ๋๋ฌธ์ ๋ฌธ๋ฒ์ด ์๋ค.
ํด๋น ๋ฌธ๋ฒ์ ์ง์ผ ์์ฑํ์ง ์์ผ๋ฉด YAML ํ์ผ๋ก ์ฝ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์, ๋ฌธ๋ฒ์ ์ ์ง์ผ์ค์ผ ํ๋ค.
๐ฌ ์ฃผ์, ๋ฌธ์์ ์์๊ณผ ๋
---------------------------------------------
`#` : ์ฃผ์
`---` : ๋ฌธ์์ ์์ (์ ํ์ฌํญ)
`...` : ๋ฌธ์์ ๋ (์ ํ์ฌํญ)
๐ฌ ๊ธฐ๋ณธ ํํ
---------------------------------------------
key: value์ด๋ฉฐ, : ๋ค์์๋ ๋ฌด์กฐ๊ฑด ๊ณต๋ฐฑ ๋ฌธ์๊ฐ ์์ผ ํ๋ค.
๐ฌ ์๋ฃํ
---------------------------------------------
`int`, `string`, `boolean`, ๋ฆฌ์คํธ, ๋งคํ์ ์ง์ํ๋ค.
์ฌ๊ธฐ์ int์ string ํ์
์ ์ค์นผ๋ผ(Scalar)๋ผ ๋ถ๋ฅด๊ณ , ๋ฐฐ์ด ํน์ ๋ฆฌ์คํธ๋ ์ํ์ค(Sequence)๋ผ ๋ถ๋ฅธ๋ค.
๋งคํ์๋ ๊ธฐ๋ณธ ํํ์ธ key-value ์ ๋ฐ hash, dictionary๊ฐ ํฌํจ๋๋ค.
#int(์ซ์)
int_type: 1
#string(๋ฌธ์์ด)
string_type: "1"
#blooean(์ฐธ/๊ฑฐ์ง)
boolean_true_type: true
boolean_false_type: false
#์ด์ธ์ yes, no๋ก ์์ฑํ๊ธฐ๋ ํ๋ค.
yaml_easy: yes
yaml_difficult: no
#๋ฆฌ์คํธ(๋ฐฐ์ด ํํ)
person:
name: Chungsub Kim
job: Developer
skills:
- docker
- kubernetes
# JSON ํ์์ "skill" : [docker, kubernetes]์ ๊ฐ๋ค.
๐ฌ ๊ฐ์ฒด
---------------------------------------------
๊ฐ์ฒด ํํ์ `key` ์์ฑ ํ ๋ ์นธ์ ๋ค์ฌ์จ์ key-value ํํ๋ก ์์ฑ์ ํด์ฃผ๊ฑฐ๋,
`key`๋ฅผ ์์ฑ ํ ์ค๊ดํธ(`{}`)๋ก ํ ๋ฒ ๋ฌถ๊ณ key-value ํํ๋ก ์์ฑํ๋ค.
key:
key: value
key: value
# ๋๋ ์ด๋ ๊ฒ๋ ๊ฐ๋
์ฑ์ ์ํด ์์ฑํ๋ค.
key: {
key: value,
key: value
}
๐ฌ Text
---------------------------------------------
์ค๋ฐ๊ฟ ํํ(`|`)๊ณผ ์ค๋ฐ๊ฟ ๋ฌด์ ํํ(`>`)์ด ์๋ค.
# |๋ ์ค๋ฐ๊ฟ ํํ์ด๋ค.
# JSON ํ์์ "comment_line_break": "Hello codestates.\nIm kimcoding.\n"๊ณผ ๊ฐ๋ค.
comment_line_break: |
Hello codestates.
Im kimcoding.
# >๋ ์ค๋ฐ๊ฟ ๋ฌด์ ํํ์ด๋ค.
# JSON ํ์์ "comment_single_line": "Hello world my first coding."๊ณผ ๊ฐ๋ค.
comment_single_line: >
Hello world
my first coding.
๐ฌ ๋ฌธ์์ด ๋ฐ์ดํ
---------------------------------------------
key-value ์์์ value์ `:`๊ฐ ๋ค์ด๊ฐ ๊ฒฝ์ฐ๋ ๋ฐ๋์ ๋ฐ์ดํ๊ฐ ํ์ํ๋ค.
# error๊ฐ ๋๋ค.
windows_drive: c:
# ์ด๋ ๊ฒ ์จ์ผ ํ๋ค.
windows_drive: "c:"
windows_drive: 'c:'
๋๋ง์ ์๊ณ ๋ผ ์คํ
์ด์ธ ์๋ฒ์ ํด๋ผ์ด์ธํธ ๋ถ๋ถ์ S3๋ก ๋ฐฐํฌํฉ๋๋ค.
ํํ ๋ฆฌ์ผ์ ์ด์ด์ ํด๋น ์ค์ต์ ์งํํฉ๋๋ค. ๊ธฐ์กด์ ๊ฐ์ง๊ณ ์์๋ ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ์ด์ฉํด ๋ด
์๋ค.
Github Actions๋ฅผ ํตํ ๋ฐฐํฌ Flow (ํด๋ผ์ด์ธํธ)
์ด๋ฒ ํด๋ผ์ด์ธํธ ๋ฐฐํฌ๋ ๊ฐ๋จํ๊ฒ 3๊ฐ์ง ๋จ๊ณ๋ก ๋๋ฉ๋๋ค.
์ด๋ฏธ ์ฌ๋ฌ๋ถ์ S3๋ ๋ฐฐํฌ๋ฅผ ์ํด ์ถฉ๋ถํ ์ค๋น๋์ด ์์์ผ๋ก, s3๋ก ํ์ผ๋ง ์ ์ ๋ฌํ๋ฉด ์ถฉ๋ถํ ๋ฐฐํฌ๋ฅผ ํ ์ ์์ต๋๋ค. ์ฐจ๊ทผ์ฐจ๊ทผ ๊ณ ๋ฏผํ๋ฉด์ ์๋ ์ฝ๋์ <?>
์ ์ฑ์๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
# .github/workflows/client.yml
name: client
on:
push:
branches:
- <?>
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout source code.
uses: actions/checkout@v2
- name: Install dependencies
run: <?>
working-directory: ./my-agora-states-client-react
- name: Build
run: <?>
working-directory: ./my-agora-states-client-react
- name: SHOW AWS CLI VERSION
run: |
<?>
- name: Sync Bucket
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_EC2_METADATA_DISABLED: true
run: |
aws s3 <?> \
--region ap-northeast-2 \
build s3://<?> \
--delete
working-directory: <?>
๊ณผ์ ๋ฅผ ์งํํ๋ฉด์, ๊ณผ์ ์ด๋ ์ถ๊ฐ ์ค๋ช
์ ๋ง๋ถ์ด๊ฒ ๋ค.
ํฐ๋ฏธ๋์์ ๋ค์๊ณผ ๊ฐ์ด ์๋ณธ ๋ ํผ์งํ ๋ฆฌ๋ฅผ ํด๋ก ํ ํ,
๋ฏธ๋ฆฌ ๋ง๋ ์๊ฒฉ ๋ ํผ์งํ ๋ฆฌ๋ก ํธ์ํด์ค๋ค.
๊ทธ๋ผ ๋ฐ๋ก Github์์ ํ์ธ ๊ฐ๋ฅํ๋ค.
๋ฐ๋ก Actions ํญ์์ ๊ธฐ์กด์ ๋ง๋ค์ด์ ธ์๋, yml
ํ์ผ์ด push
๋ฅผ ๊ฐ์งํด์ Action์ด ์๋ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด์ yml ํ์ผ์ ์์ฑํ๊ธฐ ์ ์, ํ์ฌ ๋ ํผ์งํ ๋ฆฌ์ Action์ ๋ํ key๋ฅผ ์ค์ ํด์ผ ํ๋ค.
secrets
๋ช
์ ๊ณผ์ yml
์ฝ๋๋ฅผ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, ํ๊ฒฝ ๋ณ์ ๊ฐ์ผ๋ก ์ ๋ฌ๋ฐ๊ธฐ ์ํด์ ์ ํํ๊ฒ ๊ฐ๋๋ก ์ค์ ํ๋ค.
AWS ์ ๊ทผ ํค์ ๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ์ ์ฅํ๊ธฐ ์ํด ํ๊ฒฝ ๋ณ์๋ก ์ค์ ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
๋น์ฐํ ์ด๋ ๊ฒ ํ๊ฒฝ ๋ณ์๋ก ์ค์ ํ๋ ์ด์ ๋ ๋ณด์์ ์ํจ์ด๋ฉฐ,
GitHub Secrets๋ฅผ ์ฌ์ฉํ์ฌ GitHub ์ ์ฅ์์ ์ค์ ์์ ์์ ํ๊ฒ ๊ด๋ฆฌ๋ ๊ฒ์ด๋ค.
๋ง์ฝ, AWS ์ ๊ทผ ํค๋ฅผ ์ค์ ํด์ฃผ์ง ์๋๋ค๋ฉด Action build ๊ณผ์ ์์ ์ด๋ ๊ฒ ์๋ฌ๋ฅผ ๋ณผ ์ ์๋ค.
์ด์ ๋ฐ๋ก yml
ํ์ผ์ ์์ฑํ๋ค.
GitHub Actions workflow๋ก ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๊ณ AWS S3 ๋ฒํท์ ๋ฐฐํฌํ๋ ์ค์ ์ ํ๋ ๊ฒ์ด๋ค.
name: Fronted Client Deploy
on:
push:
branches: [reference]
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout source code.
uses: actions/checkout@v2
- name: Install dependencies
run: npm install
working-directory: ./my-agora-states-client-react
- name: Build
run: npm run build
working-directory: ./my-agora-states-client-react
- name: SHOW AWS CLI VERSION
run: |
aws --version
- name: Sync Bucket
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_EC2_METADATA_DISABLED: true
run: |
aws s3 sync \
--region ap-northeast-2 \
build s3://fe-2-widrns15-s3 \
--delete
working-directory: ./my-agora-states-client-react
branches๋ ํ์ฌ ๋ฐฐํฌํ ๋ธ๋์น์ธ reference๋ก ์ค์ ํ๊ณ ,
๊ฐ๊ฐ npm install
, npm run build
๋ฅผ ์ํฉ์ ๋ง๊ฒ ๋ฃ์ด์คฌ๋ค.
ํ๊ฒฝ ๋ณ์๋ก ์ง์ ๋ AWS_ACCESS_KEY_ID
์ AWS_SECRET_ACCESS_KEY
๊ฐ์
secrets์์ ๋ถ๋ฌ์์ ํ ๋น๋๋๋ก ์๋ง๊ฒ ์ง์ ํด์ค๋ค.
์์์ key
๋ช
์ ์ ๋ ๊ฒ ์ง์ ์ด์ ๋ ์ ์ฝ๋์ ๊ฐ๊ฒ ํด์ฃผ๊ธฐ ์ํจ์ด์๋ค.
์ด์ ์ค์ ์ ๋ค ๋ง์ณค๋ค.
์ปค๋ฐ ๋ฉ์ธ์ง๋ ์๋ง๊ฒ ์์ฑํด์ฃผ๋ฉด ์์ ํ ๋์ด๋ค. ์ด์ Actions ์ด๊ธฐ ํญ์ผ๋ก ๋์๊ฐ์ ํ์ธํด๋ณด์.
์ ์์ ์ผ๋ก build
๊ฐ ๋์๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์๊ณ
์กฐ๊ธ ๊ธฐ๋ค๋ฆฌ๋ฉด ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋ ๊ฒ์ ๋ณผ ์ ์์๋ค.
๋งํฌ๋ฅผ ํ์ธํ๊ธฐ ์ ๊น์ง๋ ์๋ฌธ์ด ํ๋ ์์๋ค.
์ ๋ฒ ์ ๋์์ S3 ๋ฒํท์ ์ ๋ก๋ํ๋ ํ์ผ๋ ๊ทธ๋๋ก ์๊ณ , ๋งํฌ๋ ๊ทธ๋๋ก๋ผ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋ ์ง๊ฐ ์๋ฌธ์ด์๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฑฑ์ ๊ณผ ๋ค๋ฅด๊ฒ, ๋ฐฉ๊ธ ๋ฐฐํฌํ ํด๋ผ์ด์ธํธ ํ์ผ์ด ์ ์์ ์ผ๋ก ๋ฎ์ด์์์ ธ ์๋ ๊ฒ์ ๋ณผ ์ ์์๋ค.
ํ์ ๋ค์ ์
๋ก๋ํ๋ ํ์ผ์ ์ญ์ ํ๊ณ ์ฌ์
๋ก๋ํ๋๋, ๋ค์ ์ ๋ฒ ์ ๋ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๋ณผ ์ ์์๋ค.
CORS ์ ์ฑ ์ด ํ์ํ ์ด์
๋ธ๋ผ์ฐ์ ์์ ๊ธฐ๋ณธ์ ์ผ๋ก API๋ฅผ ์์ฒญํ ๋์, ๋ธ๋ผ์ฐ์ ์ ํ์ฌ ์ฃผ์์
API์ ์ฃผ์์ ๋๋ฉ์ธ์ด ์ผ์นํด์ผ๋ง ๋ฐ์ดํฐ๋ฅผ ์ ๊ทผํ ์ ์๊ฒ ๋์ด ์๋ค.
๋ง์ฝ ๋ค๋ฅธ ๋๋ฉ์ธ์์ API๋ฅผ ์์ฒญํด์ ์ฌ์ฉํ๋ ค๋ฉด, CORS ์ค์ ์ด ํ์ํ๋ค๋ ๊ฒ์ ์ด์ ์น์
์์ ๋ค๋ค์๋ค.
๐ก CORS
๐ก ์ถ์ฒ
๋ก์ปฌ ํ๊ฒฝ์์ ๊ฐ๋ฐํ ์ฑ์ ๊ธฐ๋ณธ์ ์ผ๋ก localhost:3000
์ผ๋ก ์์ํ๋ค.
๊ทธ๋ฌ๋ ๋์ค์ ๋ก์ปฌ ํ๊ฒฝ์์ ๊ฐ๋ฐํ ์ค์ ์๋น์ค ๋ฐ ํ๋ก์ ํธ์ ํด๋ผ์ด์ธํธ์์
์๋ฒ์ API๋ก ์์ฒญํ๊ฒ ๋๋ฉด, ์ด ํฌํธ๋ก ์์ฒญํ๋ ๊ฒ์ด ์ฐจ๋จ๋ ๊ฒ์ด๋ค.
๋ง์ผ ์ค์ ์๋น์ค๊ฐ ๋๋ ์์ฉ ์ฑ์ ์ด์ ์ค์ด๋ผ๋ฉด, ๊ตฌ์ถํ ํด๋ผ์ด์ธํธ ๋ค์
์๋ฒ์ ์ฐ๊ฒฐ๋์ด ์๋ DB์๋ ๋ผ์ด๋ธ ๋ฐ์ดํฐ(live data)๊ฐ ์์ผ ๊ฒ์ด๋ค.
์ด๋ฐ ๋ผ์ด๋ธ ๋ฐ์ดํฐ๋ ๋ฏผ๊ฐ์ฑ์ด ๋์ ๋ฐ์ดํฐ๋ค์ด ์์ฃผ์ด๊ธฐ ๋๋ฌธ์ ๋ณด์์ด ๋ฌด์๋ณด๋ค ์ค์ํ๋ค.
๊ทธ๋ฌ๋ ์๋น์ค ๋ฐ ํ๋ก์ ํธ๊ฐ ๋ชจ๋ ์ถ์ฒ์ ์ ๊ทผ์ ํ๋ฝํ๋ค๋ฉด ์ด๋ฌํ
๋ณด์์ฑ์ด ํ์ ํ ๋ฎ์์ง๊ณ , ํดํน์ ์ํ์ ๊ทธ๋๋ก ๋
ธ์ถ๋๊ฒ ๋๋ค.
๋ฐ๋ผ์ ๋ชจ๋ ๋๋ฉ์ธ์ ํ์ฉํด์๋ ์ ๋๊ณ , ํน์ ๋๋ฉ์ธ์ ํ์ฉํ๋๋ก ๊ตฌํํด์ผ ํ๋ค.
ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๊ฐ ๋ฐฑ์๋ ๊ฐ๋ฐ์์๊ฒ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์๋ฒ ๋๋ฉ์ธ์ ํ์ฉํด ๋ฌ๋ผ๊ณ
์์ฒญ์ ํด์ผ ํ๊ณ ,๋ฐฑ์๋ ๊ฐ๋ฐ์๋ ์๋ต ํค๋์ ํ์ํ ๊ฐ๋ค์ ๋ด์์ ์ ๋ฌ์ ํด์ค์ผ ํ๋ค.
์๋ฒ์์ ์ ์ ํ ์๋ต ํค๋๋ฅผ ๋ฐ์ง ๋ชปํ๋ฉด ๋ธ๋ผ์ฐ์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
Proxy
๊ทธ๋ฌ๋ ์์ ๊ณผ์ ์์ด React ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ํน์ Webpack Dev Server์์
์ ๊ณตํ๋ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด CORS ์ ์ฑ
์ ์ฐํํ ์ ์๋ค.
์ด๋ ๋ณ๋์ ์๋ต ํค๋๋ฅผ ๋ฐ์ ํ์ ์์ด ๋ธ๋ผ์ฐ์ ๋ React ์ฑ์ผ๋ก
๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ , ํด๋น ์์ฒญ์ ๋ฐฑ์๋๋ก ์ ๋ฌํ๊ฒ ๋๋ค.
์ฌ๊ธฐ์ React ์ฑ์ด ์๋ฒ๋ก๋ถํฐ ๋ฐ์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ธ๋ผ์ฐ์ ๋ก ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ์ฐ๊ธฐ ๋๋ฌธ์
๋ธ๋ผ์ฐ์ ๋ CORS ์ ์ฑ
์ ์๋ฐํ๋์ง ๋ชจ๋ฅด๊ฒ ๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ proxy ๊ธฐ๋ฅ์ ํตํด ์์ด๋ ๊ฒ์ด๋ค.
์์ ๊ทธ๋ฆผ์ proxy๋ฅผ ์ ์ฉํด ๋ธ๋ผ์ฐ์ ๋ฅผ ์์ด๊ธฐ ์ ํ๋ฆ์ด๋ค. ํ๋ก ํธ์๋๊ฐ ๊ฐ๋ฐํ React ์ฑ์์ ๋ธ๋ผ์ฐ์ ์ชฝ์ผ๋ก ์์ฒญ์ ๋ณด๋ธ๋ค. ๊ทธ๋ฌ๋ฉด ๋ธ๋ผ์ฐ์ ๋ ๋ฐฑ์๋, ์ฆ ์๋ฒ ์ชฝ์ผ๋ก ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๊ฒ ๋๋ค. ์ด๋ ์ ๊ทผ ๊ถํ์ด ์๋์ง, ์ฆ ์ถ์ฒ๊ฐ ๊ฐ์์ง ํ์ธํ๋๋ฐ ์ด๋ ๋ฐฑ์๋ ์๋ฒ๋ ์ ์์ ์ผ๋ก 200 OK ์๋ต์ ๋ธ๋ผ์ฐ์ ์๊ฒ ๋ณด๋ธ๋ค. ๋ง์ง๋ง์ผ๋ก ๋ธ๋ผ์ฐ์ ๋ ๋ฐ์ ๋ฆฌ์์ค ๋ฐ ์๋ต๊ณผ ํจ๊ป ์ถ์ฒ๊ฐ ๊ฐ์์ง ์๋์ง ํ์ธํ๊ฒ ๋๋๋ฐ, ์ด๋ ์ถ์ฒ๊ฐ ๋ค๋ฅด๋ค๋ฉด ์๋ต์ ํ๊ธฐ(CORS Error) ํ๊ณ , ์ถ์ฒ๊ฐ ๊ฐ๋ค๋ฉด ์๋ต์ ํ๊ธฐํ์ง ์๊ณ ๋ค์ ํ๋ก ํธ์๋ ์ชฝ์ผ๋ก ์๋ต์ ๋ณด๋ด์ฃผ๋ ๊ฒ์ด๋ค.
์์ ๊ทธ๋ฆผ์ proxy๋ฅผ ์ ์ฉํด ๋ธ๋ผ์ฐ์ ๋ฅผ ์์ธ ํ ํ๋ฆ์ด๋ค. React ์ฑ์์ ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด API๋ฅผ ์์ฒญํ ๋, proxy๋ฅผ ํตํด ๋ฐฑ์๋ ์๋ฒ๋ก ์์ฒญ์ ์ฐํํ์ฌ ๋ณด๋ด๊ฒ ๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ฐฑ์๋ ์๋ฒ๋ ์๋ต์ React ์ฑ์ผ๋ก ๋ณด๋ด๊ณ , React ์ฑ์ ๋ฐ์ ์๋ต์ ๋ฐฑ์๋ ์๋ฒ ๋์ ๋ธ๋ผ์ฐ์ ์๊ฒ ์ ๋ฌํ๋ค. ์ด๋ ๊ฒ ๋๋ฉด ์ถ์ฒ๊ฐ ๊ฐ์์ง๊ธฐ ๋๋ฌธ์ ๋ธ๋ผ์ฐ์ ๋ ์ด ์ฌ์ค์ ๋์น์ฑ์ง ๋ชปํ๊ณ ํ์ฉํ๊ฒ ๋๋ค.
์ค๋์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก Proxy๋ฅผ ๋ค๋ค๋ณผ ๊ฒ์ด๋ค.
๋จผ์ webpack dev server์์ ์ ๊ณตํ๋ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
webpack dev server์ proxy๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ๋ธ๋ผ์ฐ์ API๋ฅผ ์์ฒญํ ๋
๋ฐฑ์๋ ์๋ฒ์ ์ง์ ์ ์ผ๋ก ์์ฒญ์ ํ์ง ์๊ณ , ํ์ฌ ๊ฐ๋ฐ์๋ฒ์ ์ฃผ์๋ก ์ฐํ ์์ฒญ์ ํ๊ฒ ๋๋ค.
๊ทธ๋ฌ๋ฉด ์นํฉ ๊ฐ๋ฐ ์๋ฒ์์ ํด๋น ์์ฒญ์ ๋ฐ์ ๊ทธ๋๋ก ๋ฐฑ์๋ ์๋ฒ๋ก ์ ๋ฌํ๊ณ ,
๋ฐฑ์๋ ์๋ฒ์์ ์๋ตํ ๋ด์ฉ์ ๋ค์ ๋ธ๋ผ์ฐ์ ์ชฝ์ผ๋ก ๋ฐํํ๋ค.
์นํฉ ๊ฐ๋ฐ์๋ฒ์ proxy ์ค์ ์ ์๋ ์นํฉ ์ค์ ์ ํตํด์ ์ ์ฉ์ ํ์ง๋ง, CRA๋ฅผ ํตํด ๋ง๋ ๋ฆฌ์กํธ
ํ๋ก์ ํธ์์๋ package.json ์์ "proxy"
๊ฐ์ ์ค์ ํ์ฌ ์ฝ๊ฒ ์ ์ฉํ ์ ์๋๋ก ๊ตฌ์ฑ์ด ๋์ด ์๋ค.
...
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy" : "์ฐํํ API ์ฃผ์"
}
๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด์ fetch, ํน์ axios๋ฅผ ํตํด ์์ฒญํ๋ ๋ถ๋ถ์์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
// ๋ณ๊ฒฝ ์
export async function getAllfetch() {
const response = await fetch('์ฐํํ api์ฃผ์/params');
.then(() => {
...
})
}
// ๋ณ๊ฒฝ ํ
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}
webpack dev server์์ ์ ๊ณตํ๋ proxy๋ ์ ์ญ์ ์ธ ์ค์ ์ด๊ธฐ ๋๋ฌธ์,
์ข
์ข
ํด๋น ๋ฐฉ๋ฒ์ด ์ถฉ๋ถํ ์ ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ๊ธฐ๋ ํ๋ค.
๊ทธ๋์ ์๋์ผ๋ก proxy๋ฅผ ์ ์ฉํด์ค์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ,
์ด๋๋ http-proxy-middleware ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
http-proxy-middleware ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
npm install http-proxy-middleware --save
๊ทธ๋ฆฌ๊ณ React App์ src ํ์ผ ์์์ setupProxy.js ํ์ผ์ ์์ฑํ๊ณ ,
์์์ ์ค์นํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ ๋ถ๋ฌ์จ ๋ค์, ์๋์ ๊ฐ์ด ์์ฑ์ ํ๋ค.
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api', // proxy๊ฐ ํ์ํ path prameter๋ฅผ ์
๋ ฅํ๋ค.
createProxyMiddleware({
target: 'http://localhost:5000', // ํ๊ฒ์ด ๋๋ api url๋ฅผ ์
๋ ฅํ๋ค.
changeOrigin: true, // ๋์ ์๋ฒ ๊ตฌ์ฑ์ ๋ฐ๋ผ ํธ์คํธ ํค๋๊ฐ ๋ณ๊ฒฝ๋๋๋ก ์ค์ ํ๋ ๋ถ๋ถ์ด๋ค.
})
);
};
๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด์ fetch, ํน์ axios๋ฅผ ํตํด ์์ฒญํ๋ ๋ถ๋ถ์์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
๋ฐ์ ๋ถ๋ถ์ webpack dev server์์ ์ ๊ณตํ๋ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋์ ๋์ผํ๋ค.
// ๋ณ๊ฒฝ ์
export async function getAllfetch() {
const response = await fetch('์ฐํํ api์ฃผ์/params');
.then(() => {
...
})
}
// ๋ณ๊ฒฝ ํ
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}
์์ proxy์ ๋ํด ๋ฐฐ์๋ณด์์ต๋๋ค.
proxy๋ฅผ ์ ์ค์ ํ๋ฉด CORS ์ ์ฑ
์ ์ฐํํ์ฌ ๊ฐ๋ฐ ๋จ๊ณ์์๋ http ํต์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
๐ฅ Bare Minimum Requirement
์ฌ๊ธฐ ๋ ํฌ์งํ ๋ฆฌ๋ก ๋ค์ด๊ฐ git clone ํ ๋ค, ๊ณผ์ ๋ฅผ ์งํํฉ๋๋ค.
๋ฐฑ์๋์ ๊ฐ๋ฐ ์๋ฒ ์ญํ ์ ํด์ค api์, ํ๋ก ํธ์๋์ ๊ฐ๋ฐ
์๋ฒ ์ญํ ์ ํด์ค my-app์ ๊ฐ๊ฐ ์ ๊ทผํ์ฌ npm install
์ ํฉ๋๋ค.
cd api
npm install
cd my-app
npm install
์ด์ด api์ ์ ๊ทผํ ํฐ๋ฏธ๋์์๋ npm run dev
๋ฅผ,
my-app์ ์ ๊ทผํ ํฐ๋ฏธ๋์์๋ npm start
๋ฅผ ํตํด ๊ฐ๊ธฐ ๊ฐ๋ฐ ์๋ฒ๋ฅผ ์ฝ๋๋ค.
//api terminal
npm run dev
//my-app terminal
npm start
๊ทธ๋ฌ๋ฉด ํฐ๋ฏธ๋์ด ๊ฐ๊ธฐ ์ด๋ฐ ํ๋ฉด์ผ๋ก ์ฌ๋ฌ๋ถ์ ๋ง์ดํ ๊ฒ์
๋๋ค.
๊ทธ๋ค์ http://localhost:3000/
์ผ๋ก ์ด๋ํด๋ด
์๋ค.
์ด ์ํ์์ ํด๋ผ์ด์ธํธ Get all Books๋ผ๊ณ ์ฐ์ฌ ์๋ ๋ฒํผ์ ๋๋ฌ๋ด ์๋ค.
CORS ์๋ฌ๊ฐ ๋จ๋ฉฐ ์๋ต์ ์ ๋๋ก ๋ฐ์์ค์ง ๋ชปํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด ๋จ๊ณ์์๋ถํฐ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํด ํ์ด์ ํจ๊ป CORS ์๋ฌ๋ฅผ ํด๊ฒฐํด ๋๊ฐ ๊ฒ์
๋๋ค.
๊ณผ์ 1
ํ์ด์ ํจ๊ป webpack dev server์ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํด ์ฐํํ์ฌ ์๋ต์ ๋ฐ์์ต๋๋ค.
๊ณผ์ 2
๋ ํฌ์งํ ๋ฆฌ๋ก ๋ฐ์์จ ๊ณผ์ ๋ฅผ ์ดํด๋ณด๋ฉด api2๋ผ๋ ํด๋๊ฐ ์กด์ฌํ๊ณ ์์ต๋๋ค. ์ค์ ๋ก ํ๋ก์ ํธ ๋ฐ ์ค๋ฌด๋ฅผ ํ ๋, ํ๋์ ๋๋ฉ์ธ์ด ์๋ ์ฌ๋ฌ ๊ฐ์ ๋๋ฉ์ธ์์ ์๋ต์ ๋ฐ์์์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์์ต๋๋ค. ์ด๋ด ๋๋ ์ ์ฐํ๊ฒ proxy๋ฅผ ์ค์ ํ ํ์๊ฐ ์์ต๋๋ค.
๊ณผ์ ๋ ์ด 2๊ฐ๋ก ์ ๊ณผ์ ์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ณผ์ ๊ณผ ์ถ๊ฐ ์ค๋ช ์ ๋ง๋ถ์ด๊ฒ ๋ค.
๋จผ์ ๊ฒฐ๊ณผ ์ ์ฒด ์ฝ๋๋ฅผ CodeSandbox๋ก ์ฒจ๋ถํด๋๊ฒ ๋ค.
webpack dev server๋ package.json์ proxy
๋ฅผ ์ค์ ํด์ฃผ๊ณ ,
src ํด๋ ์์ ์๋ BookService์์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํด์ ๊ฐํธํ๊ฒ ๊ตฌํํ๋ค.
ํ์ ํฐ๋ฏธ๋์์ api๋ npm run dev
๋ก my-app(client)๋ npm start
๋ก ๊ฐ๊ฐ ์๋ฒ์ ํด๋ผ์ด์ธํธ ํฌํธ๋ฅผ ์ด์๋ค.
Get all Books ๋ฒํผ์ ๋๋ฌ๋ ์๋ฌ๊ฐ ์๊ธฐ์ง ์์ผ๋ฉฐ, ์ ์์ ์ผ๋ก ์ถ๊ฐ๊น์ง ๋๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๊ณผ์ 2๋ ์ถ๊ฐ์ ์ผ๋ก api2๊น์ง ๋ค๋ฃจ๋ฏ๋ก, ToDo๋ผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์
api2 ๋๋ฉ์ธ์ fetch
ํด์ค๋์ง ์ก์์ผ๋ก ํ์ธํ ์ ์๊ฒ ํ๋ค.
๊ทธ๋ฆฌ๊ณ http-proxy-middleware ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ฃผ์์ผ๋ฉฐ,
package.json์์ ์ค์ ํด์ฃผ์๋ proxy๋ฅผ ์ง์์ฃผ์๋ค.
์ด์ ์ด ์ญํ ์ ์๋ก์ด ์ปดํฌ๋ํธ setupProxy๊ฐ ํ ๊ฒ์ด๋ค.
// setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
["/api", "/api2"],
createProxyMiddleware({
target: process.env.REACT_APP_API_URL,
changeOrigin: true,
router: {
"/api2": process.env.REACT_APP_API_URL2,
},
})
);
};
๋๋ฉ์ธ์ ํ๊ฒฝ ๋ณ์๋ก ๋ง๋ค์ด์ฃผ์์ผ๋ฉฐ, ๋ ๋๋ฉ์ธ์ ํ๋์ฒ๋ผ ๋ฌถ์ด์ฃผ์๋ค.
์ดํ package.json์์ ๊ธฐ์กด webpack dev server proxy๋ฅผ ์ง์์ฃผ์๋๋ฐ๋
api, api2, client port๋ฅผ ์ ์ฒด ์ผ๊ณ ํ
์คํธํด๋ณด๋ ์ ์์ ์ผ๋ก ์งํ๋์๋ค.
ํด๋ผ์ด์ธํธ์์๋ ์ถ๊ฐ์ ์ผ๋ก ๊ตฌํํ ToDo ์ปดํฌ๋ํธ๊ฐ ๊ธฐ์กด๊ณผ ํฉ์ณ ์ ์์ ์ผ๋ก ๋ํ๋ฌ๊ณ ,
์๋ฒ์์ ์ ์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ฟ๋ ค์คฌ๋ค. ์ถ๊ฐ๋ก ํฐ๋ฏธ๋์์ ์ค์๊ฐ์ผ๋ก ์ด ์ํฉ์ ๋ณผ ์ ์์๋ค.
์ ์์ ์ผ๋ก http-proxy-middleware ๊ตฌํ์ ๋ง์น ๊ฒ์ด๋ค !
๐ก http-proxy-middleware๋ฅผ ์ฐ๋ ์ด์ _#Remind
๐ http-proxy-middleware
๋ ์น ๊ฐ๋ฐ ์, ํด๋ผ์ด์ธํธ์์ ์๋ฒ๋ก ์์ฒญ์ ๋ณด๋ผ ๋
ํ๋ก์(proxy) ์ค์ ์ ์ฝ๊ฒ ํ ์ ์๋๋ก ๋์์ฃผ๋ Node.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
์นํฉ ๊ฐ๋ฐ ์๋ฒ๋ ๋ค๋ฅธ ์๋ฒ ์ฌ์ด์ ์๋ API ์๋ฒ ๋๋ ๋ค๋ฅธ ํธ์คํธ์ ๋ํ ์์ฒญ์ ํ๋ก์ํ๋๋ฐ ์ฌ์ฉ๋๋ค.
http-proxy-middleware
๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์๋ฒ์์ ๋ฐฑ์๋ ์๋ฒ๋ก ์์ฒญ์ ํ๋ก์ํ๋ฉด, ๊ฐ์ ๋๋ฉ์ธ์์ ์์ฒญํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋๋ก ์ค์ ํ ์ ์๋ค.