- Aiden's Lab แแ ฒแแ ณแ แ ฆแแ ฅ
- Posts
- ๐ญแแ ขแจแแ ตแท แแ ตแแ ณแผ 3แแ กแแ ต แแ ตแฏแแ ณแธแแ ณแ แ ฉ แแ กแฏแแ กแแ ฉแแ ณแซ Kyverno (feat. minikube)
๐ญแแ ขแจแแ ตแท แแ ตแแ ณแผ 3แแ กแแ ต แแ ตแฏแแ ณแธแแ ณแ แ ฉ แแ กแฏแแ กแแ ฉแแ ณแซ Kyverno (feat. minikube)
Kyvernoแแ ด แแ ขแจแแ ตแท แแ ตแแ ณแผ 3แแ กแแ ตแ แ ณแฏ minikube แแ ณแฏแ แ ฅแแ ณแแ ฅแแ ฆ แแ ขแแ ฉแแ กแแ ฉ แแ ตแฏแแ ณแธแแ กแแ ง แแ ตแจแแ งแแ ฉแธแแ ตแแ ก.
์๋ ํ์ธ์, Aidenโs Lab ๋ด์ค๋ ํฐ์ ๋๋ค.
์ฌ๋ฌ ๊ฐ๋ฐ์ ๋๋ ํ์์ ๋์ผ Kubernetes ํด๋ฌ์คํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ ์ผ๊ด๋ ๊ท์น, ๋๋ ์ ์ฑ ์ ์ ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์์ ์ ์ธ ์ด์๋ฟ๋ง ์๋๋ผ ๋ณด์ ์ทจ์ฝ์ ์ ์ต์ํํ ์๋ ์๊ธฐ ๋๋ฌธ์ธ๋ฐ์. ์ฌ๊ธฐ์ ๋งํ๋ ์ ์ฑ ์ด๋ผ ํ๋ฉด...
๋ชจ๋ ์ํฌ๋ก๋์ ํน์ ๋ณด์ ์ค์ ์ ๊ฐ์ ํ๊ฑฐ๋,
๋ฆฌ์์ค ์ฌ์ฉ๋์ ์ ํํ๊ณ ,
ํ์ ๋ ์ด๋ธ์ด ๋ฌด์กฐ๊ฑด ํฌํจ๋๋๋ก ํ๋ ๋ฑ์ด ์์ต๋๋ค.
์ด๋ฐ ํด๋ฌ์คํฐ์ ์ ์ฑ ์ ๋ฌธ์๋ก๋ง ๊ด๋ฆฌํ๊ณ ๊ฐ๋ฐ์/์ด์์๊ฐ ์ง์ ์งํค๋๋ก ํ๋ค๋ฉด ์ค์(ํด๋จผ ์๋ฌ)๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ์ต๋๋ค. ๊ฒ๋ค๊ฐ ๋ฆฌ์์ค๋ฅผ ๋ฐฐํฌํ ๋๋ง๋ค Kubernetes ๋ฆฌ์์ค ๋งค๋ํ์คํ ๋ฅผ ์ผ์ผ์ด ๊ฒํ ํด์ผ ํ๋ค๋ฉด, ํด๋ฌ์คํฐ ์ด์ ํจ์จ์ฑ ์ธก๋ฉด์์๋ ์ ์ข๊ฒ ์ฃ ?
๊ทธ๋์ ํด๋ฌ์คํฐ์ ์ ์ฉ๋ ์ ์ฑ ์ ์ฝ๋๋ก ์ ์ํ๊ณ , ์์คํ ์ด ์ด๋ฅผ ์๋์ผ๋ก ๊ฐ์ ํ๋ ๋ฐฉ์์ด ๋ฑ์ฅํ์ต๋๋ค. Policy as Code(PaC)๋ผ๊ณ ํ๋ ๊ฐ๋ ์ธ๋ฐ์. ํด๋ฌ์คํฐ์ ๋ฆฌ์์ค๊ฐ ๋ฐฐํฌ๋๊ธฐ ์ ์ ์ ์๋ ์ ์ฑ ์ ์ค์ํ๋์ง ์๋์ผ๋ก ๊ฒ์ฆํ๊ณ , ์๋ฐ ์์๋ ๋ฆฌ์์ค ๋ฐฐํฌ๋ฅผ ์ฐจ๋จํด์ ํด๋ฌ์คํฐ์ ๋ณด์์ฑ๊ณผ ์์ ์ฑ์ ์ด๋์ด๋ด๋ ๋ฐฉ์์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ Kubernetes ํด๋ฌ์คํฐ์์ PaC๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ๋์จ ์คํ์์ค ์ ์ฑ ์์ง(Policy Engine)์ด ๋ฐ๋ก, Kyverno์ ๋๋ค.

Kubernetes ํด๋ฌ์คํฐ์ ์ ์ฑ ์ด ํ์ํ ๋ Kyverno๋ฅผ ์จ๋ณด์
Kyverno๋ Kubernetes ํ๊ฒฝ์์ ์ ์ฑ ์ ๊ด๋ฆฌํ๊ณ ์ํํ๊ธฐ ์ํด ์ค๊ณ๋ ์คํ์์ค ์ ์ฑ ์์ง์ ๋๋ค. ํด๋ฌ์คํฐ์ ๋ค์ด์ค๋ ๋ชจ๋ ๋ฆฌ์์ค ์์ฑ ๋ฐ ๋ณ๊ฒฝ ์์ฒญ์ ๊ฐ์งํ๊ณ , ์ ์๋ ์ ์ฑ ์ ๋ฐ๋ผ ํ์ฉ, ์ฐจ๋จ ๋๋ ์์ ์์ ์ ํ๋ '๋ฌธ์ง๊ธฐ'๋ผ๊ณ ํ ์ ์์ฃ .
๊ทธ๋ฆฌ๊ณ Kyveno๋ Kubernetes์ Admission Control ์นํ
๊ธฐ๋ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋๋ฐ์. ์ข ๋ ํ์ด์ ์ค๋ช
ํ์๋ฉด, ์ฌ์ฉ์๊ฐ kubectl apply
์ ๊ฐ์ ๋ช
๋ น์ด๋ก Kubernetes ๋ฆฌ์์ค๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ณ๊ฒฝํ๋ ค๊ณ ํ ๋ Kubernetes API ์๋ฒ๊ฐ ํด๋น ์์ฒญ์ Kyverno์๊ฒ ์ ๋ฌํด์ ์ ์ฑ
๊ฒ์ฆ์ ์์ฒญํ๋ ์์
๋๋ค. ์ด๋ Kyverno๋ ์์ฒญ ๋ด์ฉ์ ๊ฒํ ํ๊ณ ์ ์ฑ
์ ๋ฐ๋ผ์ ํ์ฉ/๊ฑฐ๋ถ ์ฌ๋ถ๋ฅผ Kubernetes API ์๋ฒ์ ๋ค์ ์๋ ค์ค์ผ๋ก์จ ์ ์ฑ
์ ๊ฐ์ ํ ์ ์๋ ๊ฒ๋๋ค.

๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๊ฐ Kubernetes ํด๋ฌ์คํฐ์ ์ ์ฑ ๊ด๋ฆฌ๋ฅผ ์ํด Kyverno๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ ๋ ๋ฌด์์ผ๊น์? Kyverno์๋ ์๋์ ๊ฐ์ด ํน์ฅ์ ์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ClusterPolicy ๋๋ Policy์ ๊ฐ์ Kubernetes CRD๋ก ์ ์ฑ ์ ์
ํด๋ฌ์คํฐ ์ ์ฒด์ ์ ์ฉ๋ ์ ์ฑ ์ ClusterPolicy๋ก, Namespace ๋จ์๋ก ์ ์ฉ๋ ์ ์ฑ ์ Policy๋ก ์ ์ ๊ฐ๋ฅํฉ๋๋ค.
์ผ๋ฐ์ ์ธ Kubernetes ๋ฆฌ์์ค๋ฅผ ๋ค๋ฃจ๋ ๊ฒ๊ณผ ๋์ผํ๊ฒ kubectl์ ์ฌ์ฉํ์ฌ ์ ์ฑ ์ ์์ฑ, ์กฐํ, ์์ , ์ญ์ ํ ์ ์์ต๋๋ค.
GitOps ์ํฌํ๋ก์ฐ๋ฅผ ์ ์ฉํ์ฌ ์ ์ฑ ์ ๋ฒ์ ์ ๊ด๋ฆฌํ๊ธฐ์๋ ์ฉ์ดํฉ๋๋ค.
์ ์ฑ ๊ฒฐ๊ณผ๋ฅผ Kubernetes ์ด๋ฒคํธ๋ PolicyReport๋ฅผ ํตํด ํ์ธ ๊ฐ๋ฅ
์ฌ์ฉ์๋
kubectl get events
๋๋kubectl describe
์ ๊ฐ์ ์ต์ํ ๋ช ๋ น์ด๋ก ์ ์ฑ ์ ๊ฒฐ๊ณผ๋ฅผ ์ฝ๊ฒ ํ์ธํ ์ ์์ต๋๋ค.์ ์ฑ ๋๋ฒ๊น ์ด๋ ํด๋ฌ์คํฐ ์ํ ๊ฐ์ฌ(Audit)๊ฐ ๋์ฑ ํธ๋ฆฌํด์ง๋๋ค.
๋ฆฌ์์ค ์์ฑ ์์ฒญ ์ฐจ๋จ ์ธ์ ๋ฆฌ์์ค ์์ ๋๋ ์์ฑ ๊ธฐ๋ฅ๋ ์ ๊ณต
์ ์ฑ ์ ์๋ฐํ๋ ์์ฒญ์ ์ฐจ๋จ(Validate)ํ๋ ๊ธฐ๋ฅ ์ธ์๋, ๋ฆฌ์์ค์ ํน์ ๋ด์ฉ์ ์๋์ผ๋ก ์ถ๊ฐํ๋ ์์ (Mutate) ๊ธฐ๋ฅ๊ณผ, ํน์ ์กฐ๊ฑด ๋ง์กฑ ์ ๋ค๋ฅธ ๊ด๋ จ ๋ฆฌ์์ค๋ฅผ ์๋์ผ๋ก ์์ฑ(Generate)ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
ํด๋ฌ์คํฐ ์ด์์ ์๋ํํ๊ณ ๊ฐ๋ฐ์์ ํธ์์ฑ์ ๋์ด๋ ๋ฐ์ ๋์์ด ๋ฉ๋๋ค.
์ด๋ฐ Kyverno์๋ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์๋๋ฐ์. ๊ทธ ์ค์์๋ ์๋ ํต์ฌ ๊ธฐ๋ฅ 3๊ฐ์ง๋ฅผ ์ด๋ฒ ์ค์ต ๊ฐ์ด๋์์ ์ง์ ์ฌ์ฉํด๋ณผ ์์ ์ ๋๋ค.
๊ฒ์ฆ(Validate)
Kyverno์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๊ท์น์ผ๋ก, ํด๋ฌ์คํฐ์ ์์ฑ๋๊ฑฐ๋ ์์ ๋๋ ๋ฆฌ์์ค๊ฐ ์ ์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธํฉ๋๋ค.
์์ (Mutate)
Kubernetes ๋ฆฌ์์ค ๋ช ์ธ ์ค ํน์ ๊ฐ์ด ๋๋ฝ๋์์ ๋ ๊ธฐ๋ณธ๊ฐ์ ์๋์ผ๋ก ์ถ๊ฐํ๊ฑฐ๋, ๋ชจ๋ ๋ฆฌ์์ค์ ๊ณตํต์ ์ธ ๋ ์ด๋ธ ๋๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ด๋ ๋ฑ ๋ฆฌ์์ค๋ฅผ ์๋์ผ๋ก ์์ ํฉ๋๋ค.
์์ฑ(Generate)
ํน์ ๋ฆฌ์์ค๊ฐ ์์ฑ๋๋ ์ด๋ฒคํธ(ํธ๋ฆฌ๊ฑฐ)์ ๋ฐ์ํ์ฌ, ๊ทธ์ ๊ด๋ จ๋ ๋ค๋ฅธ ๋ฆฌ์์ค๋ค์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค.
์: ์๋ก์ด Namespace๊ฐ ์์ฑ๋ ๋๋ง๋ค NetworkPolicy ๋๋ Role์ ํจ๊ป ์์ฑ
๋ณธ ์ค์ต ๊ฐ์ด๋๋ Kubernetes ์ ์ฑ ์ค์ ์ด๋ Kyverno์ ๋ํด ๊ถ๊ธํ์๊ฑฐ๋ ๋์ ์ ๊ณ ๋ฏผํ์๋ ๋ถ๋ค์๊ฒ ๋์์ด ๋ ์ ์๋๋ก Kyverno์ ํต์ฌ ๊ธฐ๋ฅ 3๊ฐ์ง์ ๋ํ ๋ด์ฉ์ ํจ๊ณผ์ ์ผ๋ก ์ ๋ฌํ ์ ์๋๋ก ์ค๊ณ๋์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฒ ์ค์ต์์ ๋ค๋ฃจ๋ Kyverno์ ํต์ฌ ๊ธฐ๋ฅ๋ค์ CNCF์ Kyverno Certified Associate(KCA) ์๊ฒฉ์ฆ์ ์ฃผ์ ๋ด์ฉ์ด๊ธฐ๋ ํ๋, KCA ์๊ฒฉ์ฆ์ ๊ด์ฌ์ด ์์ผ์ ๋ถ๋ค๋ ์ด๋ฒ ์ค์ต์ ์งํํด๋ณด์๋ฉด ์ํ์ ํ์ํ ์ง์์ ์ป๋ ๋ฐ์ ํฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
์ค์ต ์ค๋น: minikube ํด๋ฌ์คํฐ์ Kyverno ์ค์นํ๊ธฐ
Kyverno CLI ์ค์น
์๊น kubectl๋ก ์ ์ฑ ์์ฑ๋ถํฐ ์์ ๊น์ง ๋ชจ๋ ํ ์ ์๋ค๊ณ ํ๋๋ฐ, ์ Kyverno CLI๋ฅผ ์ค์นํด์ผ ํ ๊น์?
Kyverno ์ ์ฑ ์ ํด๋ฌ์คํฐ์ ์ง์ ์ ์ฉํ๊ธฐ ์ ์ ํ ์คํธํ๊ณ ๊ฒ์ฆํ ์ ์๋ ์ ์ฉํ ๋๊ตฌ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ ์ฑ YAML ํ์ผ๊ณผ ํ ์คํธ์ฉ ๋ฆฌ์์ค YAML ํ์ผ์ ์ฌ์ฉํด์ ํด๋น ์ ์ฑ ์ด ์๋ํ ๋๋ก ๋์ํ๋์ง ๋ฏธ๋ฆฌ ํ์ธํ ์ ์๊ฑฐ๋ ์.
Kyverno CLI๋ ๋ก์ปฌ์ ์ง์ ์ค์นํ ์๋ ์์ง๋ง, Krew๋ฅผ ํตํด kubectl์ ํ๋ฌ๊ทธ์ธ ํํ๋ก ์ค์น๋ ๊ฐ๋ฅํฉ๋๋ค.
Krew๊ฐ ๋ญ์ง, ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ถ๊ธํ์๋ค๋ฉด Aiden's Lab์ krew ํธ์ฆ์จ ๊ฐ์ด๋์์ ํ์ธํด๋ณด์ธ์.
Krew๊ฐ ์ด๋ฏธ ์ค์น๋์ด ์๋ค๊ณ ๊ฐ์ ํ๊ณ ์งํํ ๊ฒ์. kubectl ํ๋ฌ๊ทธ์ธ ํํ๋ก Kyverno CLI๋ฅผ ์ค์นํ๋ ค๋ฉด ์๋ Krew ๋ช ๋ น์ด๋ฅผ ์คํํฉ๋๋ค.
kubectl krew install kyverno

๊ทธ๋ฆฌ๊ณ ์๋ ๋ช ๋ น์ด๋ก Kyverno CLI๊ฐ ์ ์ค์น๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
kubectl kyverno version

Kyverno CLI๋ฅผ Krew๋ก ์ค์นํ๋ ์ฌ์ฉํ๊ธฐ๋ ๊ฐ๋จํ์ฃ ?
์ด์ Kyverno ๋์์ ํ์ํ ๋ฆฌ์์ค๋ค์ Kubernetes ํด๋ฌ์คํฐ์ ๋ฐฐํฌํ ์ฐจ๋ก์ ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฒ์๋ ๋น ๋ฅธ ํด๋ฌ์คํฐ ๊ตฌ์ฑ์ ์ํด minikube๋ฅผ ์ฌ์ฉํ ๊ฒ๋๋ค.
minikube๋ฅผ ์ค์นํ๊ณ Kubernetes ํด๋ฌ์คํฐ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ์ ์์ง ์ต์์น ์์๋ ๊ฑฑ์ ๋ง์ธ์. minikube ์๊ฐ๋ถํฐ ์ค์น, ํ์ฉ๋ฒ๊น์ง ์์ธํ ๋ค๋ฃฌ Aiden's Lab์ minikube ํธ์ฆ์จ ๊ฐ์ด๋๋ฅผ ๋ณด์๋ฉด ๊ธ๋ฐฉ ๋ฐ๋ผ์ค์ค ์ ์์ ๊ฒ๋๋ค.
๊ทธ๋ผ ๋ฐ๋ก ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ๋ด ์๋ค.
minikube ํด๋ฌ์คํฐ์์ Helm์ผ๋ก Kyverno ๋ฐฐํฌ
์ฐ๋ฆฌ๋ Kyverno๋ฅผ ํด๋ฌ์คํฐ์ ๋ฐฐํฌํ ๋ Helm์ ์ฌ์ฉํ ๊ฒ๋๋ค. ์๋ง ์์๋ ๋ถ๋ค์ด ๊ณ์๊ฒ ์ง๋ง, Helm์ Kubernetes์ ๋ฐฐํฌ๋๋ ํ๋ก์ ํธ์ ๊ฐ ๋ฆฌ์์ค์ YAML ํ์ผ์ ๋ก์ปฌ์ ์ ์ฅํ์ง ์๊ณ ๋ ์๊ฒฉ์์ ๋ถ๋ฌ์ CLI ํ๊ฒฝ์์ ์์ฑ, ๋ฒ์ ๊ด๋ฆฌ, ๊ณต์ ๊น์ง ํ ์ ์๋ Kubernetes ํจํค์ง ๋งค๋์ ํด์ ๋๋ค.
Helm์ ์ฌ์ฉํ๋ฉด Kyverno๋ฅผ ํด๋ฌ์คํฐ์ ๊ฐํธํ๊ฒ ๋ฐฐํฌํ ์ ์๋๋ฐ์. Kyverno์ ๊ณต์ ๋ฌธ์์์๋ ์ด์ฒ๋ผ ๊ถ์ฅํ๊ณ ์์ผ๋ฏ๋ก, ์ ํฌ๋ Helm์ผ๋ก Kyverno๋ฅผ ๋ฐฐํฌํด๋ณด๊ฒ ์ต๋๋ค.
๋ง์ฝ ์ค์ต ํ๊ฒฝ์ Helm์ด ์ค์น๋์ด ์์ง์๋ค๋ฉด ์๋์ ๊ฐ์ด Helm์ ๋จผ์ ์ค์นํฉ๋๋ค. (Ubuntu ํ๊ฒฝ ๊ธฐ์ค)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด Helm ๋ช ๋ น์ด๋ฅผ ์คํํ์ฌ minikube ํด๋ฌ์คํฐ์ Kyverno๋ฅผ ๋ฐฐํฌํฉ๋๋ค.
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace

๋ฐฐํฌ๊ฐ ์๋ฃ๋๋ฉด Kyverno์ ๊ตฌ์ฑ์์๋ค์ด ์ ์์ ์ผ๋ก ์คํ ์ค์ธ์ง ํ์ธํด์ผ ํ๋๋ฐ์. kubectl -n kyverno get pods
๋ช
๋ น์ด๋ก ํ์ฌ ๋ฐฐํฌ๋ ๋ชจ๋ Kyverno ๊ด๋ จ Pod์ ํ์ฌ ์ํ๋ฅผ ๋ณด๋ฉด ๋ฉ๋๋ค.
์๋์ ๊ฐ์ด Kyverno ๊ด๋ จ Pod๊ฐ ๋ชจ๋ READY
์ํ์ด๋ฉด์ STATUS
๋ Running
์ด๋ฏ๋ก, Kyverno ๊ตฌ์ฑ์์๋ค์ด ๋ชจ๋ ์ ๋์ ์ค์ธ ๊ฑธ ์ ์ ์๋ค์.

Kyverno CLI ์ค์น์ Kyverno ๋ฐฐํฌ๊ฐ ๋ชจ๋ ์๋ฃ๋์์ผ๋, ์ด์ Kyverno์ ํต์ฌ ๊ธฐ๋ฅ ์ค์ต์ ์์ํด๋ณด๊ฒ ์ต๋๋ค.
ํต์ฌ ๊ธฐ๋ฅ ์ค์ต 1 - ๋ฆฌ์์ค ์์ฑ ๊ท์น ๊ฒ์ฆ(Validate)
validate
๊ท์น์ ์ ์๋ ์ ์ฑ
์ ์๋ฐํ๋ ๋ฆฌ์์ค ์์ฒญ์ ์ฐจ๋จํ์ฌ Kubernetes ํด๋ฌ์คํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๊ณ , ์ ์ฌ์ ์ธ ๋ณด์ ์ํ๋ ์ค์ฌ์ค๋๋ค.
์๋ฅผ ๋ค์ด, '๋ชจ๋ Pod๋ non-root ์ ์ ๋ก ์คํํด์ผ ํ๋ค'๊ฑฐ๋, '๋ชจ๋ Ingress๋ HTTPS๋ง ํ์ฉํด์ผ ํ๋ค'์ ๊ฐ์ ๋ณด์ ๋ชจ๋ฒ์ฌ๋ก๋ฅผ ์ ์ฑ
์ผ๋ก ๋ง๋ค์ด ๊ฐ์ ํ ์ ์์ฃ . ๋ํ, '๋ชจ๋ ๋ฆฌ์์ค์๋ owner
๋ ์ด๋ธ์ด ์์์ด์ผ ํ๋ค'์ ๊ฐ์ด ์กฐ์ง ๋ด๋ถ์ ๊ด๋ฆฌ ํ์ค์ ์ ์ฉํ ์๋ ์์ต๋๋ค.
๊ทธ๋ผ ์ด์ validate
๊ท์น์ ํฌํจํ๋ Kyverno์ ClusterPolicy๋ฅผ ์ง์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ์๋์ ๊ฐ์ ์๊ตฌ์ฌํญ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ์.
ํด๋ฌ์คํฐ์ ์์ฑ๋๋ ๋ชจ๋ Pod์๋ ๋ฐ๋์
test-for-kyverno/name
๋ ์ด๋ธ์ด ํฌํจ๋์ด์ผ ํจ๋ณธ ์ ์ฑ ์๋ฐ ์ ๋ฆฌ์์ค ์์ฑ ์ฐจ๋จ
๊ทธ๋ฆฌ๊ณ ํด๋น ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๊ธฐ ์ํ ClusterPolicy ์์ ์ฝ๋(require-label.yaml
)๋ ์๋์ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-label
spec:
validationFailureAction: Enforce # ์ ์ฑ
์๋ฐ ์ ๋ฆฌ์์ค ์์ฑ์ ์ฐจ๋จ
rules:
- name: check-for-name-label
match:
resources: # ์ ์ฑ
์ด ์ ์ฉ๋ ๋ฆฌ์์ค ์ข
๋ฅ ์ง์
kinds:
- Pod
validate:
message: "Pod์๋ ๋ฐ๋์ test-for-kyverno/name ๋ ์ด๋ธ์ด ํ์ํฉ๋๋ค."
pattern:
metadata:
labels:
test-for-kyverno/name: "?*" # ์ด ๋ ์ด๋ธ์ ์กด์ฌ ์ฌ๋ถ๋ง ๊ฒ์ฌ
๊ทธ๋ฆฌ๊ณ ์๋ ๋ Deployment YAML ์์ ๋ ๊ฐ๊ฐ ์ ์ ์ฑ ์ ์๋ฐ ๋ฐ ํต๊ณผ๋๋ ํ ์คํธ์ฉ ์ฝ๋์ ๋๋ค.
์ ์ฑ
์ ์๋ฐ๋๋ Deployment(test-validate-fail.yaml
):
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment-fail
namespace: kyverno-demo
spec:
replicas: 1
selector:
matchLabels:
app: my-test-app
template:
metadata:
# 'test-for-kyverno/name' ๋ ์ด๋ธ์ด ์์ผ๋ฏ๋ก validate ์ ์ฑ
์ ์ํด ์์ฑ ๊ฑฐ๋ถ
labels:
app: my-test-app
spec:
containers:
- name: nginx
image: nginx:latest
์ ์ฑ
์ ๋ฐ๋ฅด๋ Deployment(test-validate-success.yaml
):
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment-success
namespace: kyverno-demo
spec:
replicas: 1
selector:
matchLabels:
test-for-kyverno/name: my-successful-app
template:
metadata:
# 'test-for-kyverno/name' ๋ ์ด๋ธ์ด ์์ผ๋ฏ๋ก validate ์ ์ฑ
ํต๊ณผ
labels:
test-for-kyverno/name: my-successful-app
spec:
containers:
- name: nginx
image: nginx:latest
ํ
์คํธ์ฉ Deployment YAML ์ฝ๋์์ ๋ณผ ์ ์๋ฏ์ด, ์ฐ๋ฆฌ๊ฐ ํ
์คํธํ ๋ฆฌ์์ค๋ค์ kyverno-demo
Namespace์ ๋ฐฐํฌํ ์์ ์ด๋ฏ๋ก kubectl create ns kyverno-demo
๋ช
๋ น์ด๋ฅผ ์คํํด์ ํด๋น Namespace๋ฅผ ๋จผ์ ์์ฑํด์ฃผ์ธ์.
์ ๋ ์ค์ต์ ์ํด ๋ณ๋์ ํด๋๋ฅผ ์์ฑํ๊ณ , ์ ์ฑ
์์ ์ฝ๋๋ ๋ชจ๋ policies
ํด๋์ ์ ์ฅํ๊ณ , ํ
์คํธ์ฉ ๋ฆฌ์์ค ํ์ผ๋ค์ ๋ ๋ค๋ฅธ resources
ํด๋ ์์ ์ ์ฅํ๋๋ฐ์. ์ด์ ์ค์ ๋ก ์ ์ฑ
์ ๋ฐฐํฌํ๊ธฐ ์ ์, ์๋ Kyverno CLI ๋ช
๋ น์ด๋ฅผ ํตํด ์ ์ฑ
์ด ์ด๋ป๊ฒ ์ ์ฉ๋๋์ง ํ
์คํธํด๋ณด๊ฒ ์ต๋๋ค.
kubectl kyverno apply {Policy ํ์ผ๋ช
} -r {ํ
์คํธ ๋ฆฌ์์ค ๊ฒฝ๋ก}
์ ๋ช
๋ น์ด ๋ง์ง๋ง์ -t
์ต์
์ ์ฃผ๋ฉด, ์๋์ ๊ฐ์ด ์ ์ฑ
ํ
์คํธ ๊ฒฐ๊ณผ๊ฐ ํ ํ์์ผ๋ก ๋ณด๊ธฐ ์ฝ๊ฒ ํ์๋ฉ๋๋ค.

์ฐ๋ฆฌ๊ฐ ์๋ํ ๋๋ก, test-validate-fail.yaml
๋ฆฌ์์ค๋ ์ ์ฑ
์๋ฐ, test-validate-success.yaml
๋ฆฌ์์ค๋ ์ ์ฑ
ํต๊ณผ๋ผ๋ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ณ ์๋ค์. ๊ทธ๋ผ ์ด์ ์ค์ ๋ก ํด๋ฌ์คํฐ์ ์ ์ฑ
์ ๋ฐฐํฌํ ๋ค์, ํ
์คํธ์ฉ ๋ฆฌ์์ค๋ค๋ ๋ฐฐํฌํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ์๋ ๋ช
๋ น์ด๋ก require-label.yaml
์ ์ฑ
์ ๋ฐฐํฌํฉ๋๋ค.
โ ๏ธClusterPolicy ์ ์ฉ ์ฃผ์!
์์ผ๋ก ๋ฐฐํฌํ Kyverno์ ClusterPolicy๋ ํด๋ฌ์คํฐ์ ๋ฐฐํฌ๋ ์ ์ฒด Pod์ ํน์ ๋ ์ด๋ธ์ด ํฌํจ๋๋๋ก ๊ฐ์ ํ๋ฏ๋ก ๋ฐ๋์ ์ค์ต์ฉ ํด๋ฌ์คํฐ์์ ์งํํด์ฃผ์ธ์.
ํด๋น ํด๋ฌ์คํฐ์ ์ด๋ฏธ ๋ค๋ฅธ Pod๊ฐ ์คํ ์ค์ด๋ผ๋ฉด ClusterPolicy์ ์ํฅ์ ๋ฐ์ ์ ์์ต๋๋ค.
kubectl apply -f policies/require-label.yaml
kubectl๋ก ๋ฐฐํฌํ Kyverno์ ClusterPolicy๋ ์๋์ ๊ฐ์ด ์กฐํํ ์ ์์ต๋๋ค.

๊ทธ ๋ค์, ์๊น Kyverno CLI ํ
์คํธ ๋ ์ ์ฑ
์ ์๋ฐ๋์๋ test-validate-fail.yaml
๋ฆฌ์์ค๋ฅผ kubectl apply
๋ช
๋ น์ด๋ก ๋ฐฐํฌํด๋ณด๊ฒ ์ต๋๋ค.

๋ณด์ด๋ ๊ฒ์ฒ๋ผ ๋ฆฌ์์ค ๋ฐฐํฌ๊ฐ ๋งํ์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ํด๋น validate
์ message
ํ๋์ ์ง์ ํ๋ ์๋ด ๋ฉ์์ง๋ ํจ๊ป ๋์ค๊ณ ์๋ค์! ์ด๋ ๊ฒ Kyverno์ validate
๊ท์น์ ๋ฆฌ์์ค ์์ฑ ์ ์ฌ์ฉ์์๊ฒ ์ ์ฑ
์ ์๋ฐ๋๋ ์ฌํญ์ ์๋ ค์ฃผ๊ณ , ์ ์ฑ
์ ๋ฐ๋ฅด๋๋ก ์ ๋ํ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
ํต์ฌ ๊ธฐ๋ฅ ์ค์ต 2 - ๋ฆฌ์์ค ์๋ ์์ (Mutate)
๋ค์์ผ๋ก ์์๋ณผ ๊ท์น์ mutate
์
๋๋ค. ๊ฐ๋ฐ์๋ ์ด์์๊ฐ Kubernetes ํด๋ฌ์คํฐ์ ๋ฆฌ์์ค๋ฅผ ์์ฑํ ๋ ํ์ํ ํน์ ํ๋๋ฅผ ๋ช
์ํ์ง ์์์ ๊ฒฝ์ฐ, mutate
๊ท์น์ ํตํด ์๋์ผ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ์ ์๋๋ฐ์.
์๋ฅผ ๋ค๋ฉด Pod์ imagePullPolicy
ํ๋ ๊ฐ์ด ๋ช
์๋์ง ์์๋ค๋ฉด IfNotPresent
๊ฐ์ ์๋์ผ๋ก ๋ฃ์ด์ฃผ๊ฑฐ๋, ๋ชจ๋ Pod์ resouces/requests
๊ฐ์ ์๋์ผ๋ก ์ถ๊ฐํ๋ ๋ฑ์ ์์
์ด ๊ฐ๋ฅํ ๊ฑฐ์ฃ . ํด๋ฌ์คํฐ์ ์์ ์ฑ๊ณผ ์์ ํจ์จ์ฑ์ ๋์ด๊ธฐ ์ํด ํ์ฉ๋๋ ๊ท์น์
๋๋ค.
๊ทธ๋ผ mutate
๊ท์น์ ์ค์ตํด๋ณด๊ฒ ์ต๋๋ค. ์๋์ ๊ฐ์ ์๊ตฌ์ฌํญ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ์.
๋ชจ๋ ํด๋ฌ์คํฐ์ ์๋ก์ด Pod๊ฐ ์์ฑ๋ ๋๋ง๋ค
managed-by
๋ผ๋ ์ด๋ ธํ ์ด์ ์ด ํ์๋ก ์กด์ฌํด์ผ ํจmanaged-by
ํ๋์ ๊ธฐ๋ณธ๊ฐ์kyverno
์ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๋ ClusterPolicy(add-annotation.yaml
)๋ ์๋์ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-annotation-simple
spec:
rules:
- name: add-managed-by-annotation
match:
resources:
kinds:
- Pod
mutate:
patchStrategicMerge: # ์๋ ๋ฆฌ์์ค ๋ด์ฉ์ ์์ฑ๋ ๋ฆฌ์์ค ๋ช
์ธ์ ๋ณํฉ
metadata:
annotations:
# 'managed-by' ์ด๋
ธํ
์ด์
์ด ์์ผ๋ฉด(+) ์ง์ ๊ฐ(kyverno)์ ์ถ๊ฐ
+(managed-by): kyverno
์๊น 'ํต์ฌ ๊ธฐ๋ฅ 1'์์ ์ฌ์ฉํ๋ ํ
์คํธ์ฉ Deployment๋ฅผ ๋ค์ ์ค์ต์ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ Kyverno CLI์ apply
๋ช
๋ น์ด๋ก add-annotation.yaml
๋ก ์ ์ํ mutate
๊ท์น์ด ์ ์ ์๋ํ๋์ง ํ
์คํธํด๋ณด๊ฒ ์ต๋๋ค. kyverno apply
๋ช
๋ น์ด ์์์ 'ํต์ฌ ๊ธฐ๋ฅ 1'์์ ์ด๋ฏธ ์ดํด๋ดค์์ฃ ?


๋ช
๋ น์ด๋ฅผ ์คํํ๋ฉด mutate
๊ท์น์ผ๋ก ์ธํด ๋ ๊ฐ์ Deployment ๋ชจ๋ managed-by
์ด๋
ธํ
์ด์
์ผ๋ก kyverno
๊ฐ์ด ์๋์ผ๋ก ๋ค์ด๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ฐธ๊ณ ๋ก, kyverno apply
๋ ํฐ๋ฏธ๋์์์ ๋์ํ๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๊ฐ ์คํํ ๋ช
๋ น์ด๋ก ์ค์ Deployment YAML ํ์ผ์ด ์์ ๋ ๊ฒ์ ์๋๋๋ค.
์ด์ ํด๋น ClusterPolicy๋ฅผ ์ค์ต์ฉ ํด๋ฌ์คํฐ์ ๋ฐฐํฌ ํ, test-validate-success.yaml
ํ์ผ์ Deployment๋ฅผ ๋ฐฐํฌํด๋ณด๊ฒ ์ต๋๋ค. (์ฐ๋ฆฌ๊ฐ ์ด๋ฏธ require-label
ClusterPolicy๋ฅผ ํด๋ฌ์คํฐ์ ๋ฐฐํฌํ๊ธฐ ๋๋ฌธ์ test-validate-fail.yaml
์ Deployment๋ test-for-kyverno/name
label์ ์ถ๊ฐํ์ง ์๋ ์ด์ ๋ฐฐํฌํ ์ ์์ต๋๋ค.)
๋จผ์ add-annotation.yaml
ํ์ผ์ ์ ์ฑ
์ ๋ฐฐํฌํฉ๋๋ค.

๊ทธ๋ฆฌ๊ณ test-validate-success.yaml
ํ์ผ์ Deployment๋ฅผ ๋ฐฐํฌํ ๋ค์, kubectl describe
๋ช
๋ น์ด๋ก ๋ฐฐํฌ๋ Deployment์ ๋ช
์ธ๋ฅผ ํ์ธํด๋ณด๊ฒ ์ต๋๋ค. ์ง๊ธ ์์ YAML ํ์ผ์๋ managed-by
์ด๋
ธํ
์ด์
์ด ๋ช
์๋์ง ์์๋ค๋ ์ ๊ธฐ์ตํด์ฃผ์ธ์!

test-validate-success.yaml
์ Deployment๊ฐ ์ ์ ๋ฐฐํฌ๋์๊ณ , managed-by
์ด๋
ธํ
์ด์
์ kyverno
๊ฐ์ด ์๋์ผ๋ก ์ถ๊ฐ๋์์ต๋๋ค! ์ด๋ ๊ฒ mutate
๊ท์น์ผ๋ก Kubernetes ๋ฆฌ์์ค์ ๊ผญ ๋ช
์๋์ด์ผ ํ๋ ํ๋์ ๊ธฐ๋ณธ๊ฐ์ ์๋์ผ๋ก ์ถ๊ฐํ์ฌ ๋ฆฌ์์ค ๋ช
์ธ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ ์ ์์์ ํ์ธํ์ต๋๋ค.
ํต์ฌ ๊ธฐ๋ฅ 3 - ํ์ ๋ฆฌ์์ค ์๋ ์์ฑ(Generate)
๋ง์ง๋ง์ผ๋ก Kyverno์ ํต์ฌ ๊ธฐ๋ฅ generate
๊ท์น์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค. ํน์ ๋ฆฌ์์ค๊ฐ ์์ฑ๋ ๊ฒฝ์ฐ, ํ์ํ์ง๋ง ์ง์ ์์ฑํ๊ธฐ์ ๋ฐ๋ณต ์์
์ด ๋ ์ ์๋ ๋ค๋ฅธ ๋ฆฌ์์ค๋ค์ ์๋์ผ๋ก ์์ฑํ๋ ๊ธฐ๋ฅ์ธ๋ฐ์.
์๋ฅผ ๋ค๋ฉด ์๋ก์ด ์ฌ์ฉ์๊ฐ ์์ฑ๋ ๋๋ง๋ค ํด๋น ์ฌ์ฉ์๋ฅผ ์ํ ๊ธฐ๋ณธ Role๊ณผ RoleBinding์ ์๋์ผ๋ก ๋ง๋ค์ด ์ค ์ ์์ต๋๋ค. ๋ณต์กํ ์ค์ ๊ณผ์ ์ ์๋ํํ๋ฉด์ ์ผ๊ด์ฑ๋ ์ ์งํ ์ ์์ด ์ ์ฉํ ๊ท์น์ ๋๋ค.
์ฐ๋ฆฌ๋ ์๋ ์๊ตฌ์ฌํญ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ์.
์๋ก์ด Namespace๊ฐ ์์ฑ๋ ๋๋ง๋ค ํด๋น Namespace๋ฅผ ์ํ NetworkPolicy ์๋ ์์ฑ
์ด NetworkPolicy๋ ํด๋น Namespace์ ์ํ ๋ชจ๋ Pod์ ์ธ๋ถ๋ก ํฅํ๋ ํต์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฐจ๋จ
์ด ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๋ ClusterPolicy(generate-network-policy.yaml
)๋ ์๋์ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-network-policy
spec:
rules:
- name: generate-default-deny-policy
# Namespace ์์ฑ์ผ๋ก ํด๋น ๊ท์น์ด ํธ๋ฆฌ๊ฑฐ๋จ์ ์ ์
match:
resources:
kinds:
- Namespace
# ์ match ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด ์๋ ๋ฆฌ์์ค๋ฅผ ์์ฑ
generate:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: default-deny-all # ์์ฑ๋ NetworkPolicy์ ์ด๋ฆ
namespace: "{{request.object.metadata.name}}" # ํธ๋ฆฌ๊ฑฐ๋ Namespace์ ์ด๋ฆ์ ์ฌ์ฉ
synchronize: true # Namespace๊ฐ ์ญ์ ๋๋ฉด ์ด NetworkPolicy๋ ํจ๊ป ์ญ์
data:
spec:
# ํด๋น Namespace์ ๋ชจ๋ Pod์ ์ด ์ ์ฑ
์ ์ ์ฉ
podSelector: {}
# ์ธ๋ถ๋ก ๋๊ฐ๋(Egress) ๋ชจ๋ ํธ๋ํฝ์ ์ฐจ๋จ
policyTypes:
- Egress
๊ทธ๋ผ ํด๋น ClusterPolicy๋ฅผ ๋ฐ๋ก ํด๋ฌ์คํฐ์ ๋ฐฐํฌํด๋ณด๊ฒ ์ต๋๋ค.

๊ทธ๋ฆฌ๊ณ test-for-generate-rule
์ด๋ผ๋ ์ด๋ฆ์ Namespace๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.

ํด๋น Namespace์ NetworkPolicy๋ฅผ ์กฐํํด๋ณด๋ฉด...

generate-network-policy.yaml
ClusterPolicy์์ ์ ์ํ๋ default-deny-all
NetworkPolicy๊ฐ ์๋์ผ๋ก ์์ฑ๋์์ต๋๋ค! ๊ทธ๋ฆฌ๊ณ generate.kyverno.io/policy-name
๋ฐ generate.kyverno.io/rule-name
Label์ ๊ฐ์ ๋ณด๋ฉด ์ด๋ค Kyverno ์ ์ฑ
๊ณผ ๊ท์น์ผ๋ก ์ธํด ์์ฑ๋์๋์ง๋ ์ ์ ์๋ค์.
์์ ์ฌ๋ก์์ ๋ดค๋ ๊ฒ ์ด์ธ์๋, ConfigMap์ด๋ Secret ๋ฑ ์ถ๊ฐ๋ก ์์ฑ์ด ํ์ํ์ง๋ง ์์นซํ๋ฉด ๋ฐ๋ณต ์์
์ด ๋ ์ ์๋ ๋ฆฌ์์ค๋ค ์ญ์ Kyverno์ generate
๊ท์น์ผ๋ก ํ ๋ฒ์ ์์ฑ ๊ฐ๋ฅํฉ๋๋ค.
๋ง๋ฌด๋ฆฌ
Kyverno์ ClusterPolicy๋ ํด๋ฌ์คํฐ ์ ์ฒด์ ์ํฅ์ ์ฃผ๋ ๋ฆฌ์์ค์ด๋ฏ๋ก, ์ค์ต์ฉ ํด๋ฌ์คํฐ์ ๋ฐฐํฌํ๋ ์ ์ฑ
์ ๋ชจ๋ ์ ๊ฑฐํ ๊ฒ์ ๊ถํด๋๋ฆฝ๋๋ค. Kubernetes ๊ฒฝํ์ด ์์ผ์๋ค๋ฉด ์ต์ํ kubectl delete
๋ช
๋ น์ด๋ก ํ ๋ฒ์ ์ ๊ฑฐ ๊ฐ๋ฅํฉ๋๋ค.
kubectl delete clusterpolicy require-label add-annotation-simple generate-network-policy

์ง๊ธ๊น์ง Kyverno์ ํต์ฌ ๊ธฐ๋ฅ์ด์ ๊ท์น 3๊ฐ์ง๋ฅผ ์์ธํ ์ดํด๋ณด๊ณ ์ค์ต๊น์ง ์งํํ์ต๋๋ค. validate
, mutate
, generate
๊ท์น์ ๋
๋ฆฝ์ ์ผ๋ก๋ ๊ฐ๋ ฅํ์ง๋ง, ์๋ก ์กฐํฉํ์ฌ ์ฌ์ฉ๋ ๋ ๋์ฑ ์ ๊ตํ๊ณ ํจ๊ณผ์ ์ธ ์ ์ฑ
์ ๊ตฌ์ฑํ ์ ์๋๋ฐ์.
ํน์ ๋ฆฌ์์ค๊ฐ ์์ฑ๋ ๋ mutate
๋ก ๊ธฐ๋ณธ๊ฐ์ ์ถ๊ฐํ๊ณ , validate
๋ก ๋ค๋ฅธ ํ์ ์กฐ๊ฑด์ ๊ฒ์ฆํ ๋ค, generate
๋ก ๊ด๋ จ๋ ๋ณด์กฐ ๋ฆฌ์์ค๋ฅผ ํจ๊ป ์์ฑํ๋ ๋ณตํฉ ์๋๋ฆฌ์ค ๊ตฌํ์ด ๊ฐ๋ฅํ ๊ฒ์ด์ฃ . ์ด๋ฒ ๊ธ์ Kyverno๋ฅผ ๋ง ์์ํ ๋ถ๋ค์ ์ํด ์์ฑํ ๊ฒ์ด์ด์ ์ด๋ฐ ์ฌํ ์๋๋ฆฌ์ค๊น์ง ์งํํ์ง ๋ชปํ์ง๋ง, ์ถํ์ ๋ค๋ค๋ณผ ๊ธฐํ๊ฐ ์์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.
์ด๋ฒ ์ค์ต ๊ฐ์ด๋๋ฅผ ๋ฐ๋ผํ์๋ฉด์ ์ด๋์ Kyverno์ Policy as Code์ ๋ํ ๊ธฐ๋ณธ ์ง์์ ์ตํ์ จ์ ๊ฑฐ๋ ์๊ฐ์ด ๋ญ๋๋ค. ํน์ ์ด๋ฒ ์ฃผ์ ์ ๊ด๋ จํด์ ์ข ๋ ๋ค๋ค์ผ๋ฉด ํ๋ ๋ด์ฉ์ด๋ ๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์ธ์ ๋ ์๋ ํผ๋๋ฐฑ ์์์ ๋จ๊ฒจ์ฃผ์ธ์.
๊ทธ๋ผ ๋ค์์ ๋ ํฅ๋ฏธ๋ก์ด ์ฃผ์ ๋ก ์ฐพ์์ค๊ฒ ์ต๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
โจ์ด๋ฒ ๋ด์ค๋ ํฐ๋ ์ด๋ ์ จ๋์?
์ด๋ฒ ๊ธ์์ ๋ค๋ฃฌ ์ฃผ์ ์ ๋ํด ์ด๋ป๊ฒ ์๊ฐํ๋์ง ์๋ ค์ฃผ์ธ์! ๋ด์ค๋ ํฐ๋ฅผ ๋ ๋์ ๋ฐฉํฅ์ผ๋ก ๊ฐ์ ํ๊ธฐ ์ํด ์๋ ํผ์์ ์งง์ ํผ๋๋ฐฑ์ ๋ฐ๊ณ ์์ด์.
๐ ํผ๋๋ฐฑ ๋ณด๋ด๊ธฐ (1~2๋ถ ์์)
์ฌ๋ฌ๋ถ๋ค์ ์์คํ ์๊ฒฌ์ Aidenโs Lab ๋ด์ค๋ ํฐ์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค!
๐ญAidenโs Lab์์ ๋ ๋ง์ ์ํฐํด์ ๋ง๋๋ณด์ธ์
๋ฐํ๋ ๋ด์ค๋ ํฐ๋ฅผ ์์นด์ด๋นํ๊ณ ๋ค์ํ ์ ๋ณด๋ฅผ ๊ณต์ ํ๋ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ด์ ์ค์ ๋๋ค.