์ฟ ๋ฒ๋คํฐ์ค๋ ์ ์ธํ ํจ๋ฌ๋ค์์ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌ ๋ฐ ์ด์์ ๋ณด๋ค ์ฝ๊ฒํ ์ ์๋๋ก ๋์์ค๋๋ค. ํ์ง๋ง ์์คํ ๊ฐ๋ฐ ์ธก๋ฉด์์๋ ์ฟ ๋ฒ๋คํฐ์ค๋ผ๋ ์๋ก์ด ๊ฐ๋ ๋ฐ ์ํคํ ์ณ๋ฅผ ์ดํดํด์ผํ๊ณ ์ด๋ก ์ธํด ์๋น์ค์ ๋ณต์ก๋ ๋ํ ์ฆ๊ฐํ๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ฟ ๋ฒ๋คํฐ์ค ํ๋ซํผ์ ์ ๊ณตํ๋ Provider์ ์ ์ฅ์์๋ ์ด์์ ์์ด ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ฑ ๋ฐ ๋ฐฐํฌ ๋ฐฉ๋ฒ์ ์ถ์ํ์์ผ ์ ๊ณตํ ํ์์ฑ์ด ์กด์ฌํฉ๋๋ค.
ํ์ง๋ง ์ถ์ํ๋ฅผ ๋ฌ์ฑํ ๋, ์ด๋ ์ ๋์ ์ถ์ํ๋ฅผ ์ ๊ณตํ ์ง์ ๋ํ ๊ณ ๋ฏผ์ด ํ์ํฉ๋๋ค. ๊ณ ์์ค์ ์ถ์ํ๋ฅผ ๋ฌ์ฑํ๋ฉด ๊ฐ๋ฐ์๊ฐ ์ด์์ ์์ด ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค์ํ๋๋ก ๋ง๋ค ์ ์์ง๋ง, ์ง๋์น ์ถ์ํ๋ ์ธ๋ถ ์ค์ ์ ๋ํด ์ ๊ทผ์ ์ด๋ ต๊ฒํ๊ณ , ๋ซํ ์์คํ ์ด ๋ ์ํ์ด ์กด์ฌํฉ๋๋ค. ๋ฐ๋ผ์ ์ด๋์ ๋์ ์ถ์ํ๋ฅผ ๋ฌ์ฑํ ์ง์ ๋ํ ๊ณ ๋ฏผ๊ณผ ์ค๊ณ๊ฐ ๋๋ฐ๋์ด์ผ ํฉ๋๋ค.
์ถ์ํ๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ์ผ๋ฐ์ ์ผ๋ก 2๊ฐ์ง ๋ฐฉ๋ฒ์ด ์กด์ฌํฉ๋๋ค. ์ฒซ ๋ฒ์งธ๋ ์ฟ ๋ฒ๋คํฐ์ค๋ฅผ ์ธ๋ถ๋ก ๋ถํฐ ๊ฐ์ถ๊ณ ํ๋ซํผ์ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ ์ฟ ๋ฒ๋คํฐ์ค์ ์กด์ฌ๋ฅผ ์์ง ๋ชปํ์ฑ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ ๋ฒ์งธ๋ ์ฟ ๋ฒ๋คํฐ์ค API ์๋ฒ๋ฅผ ํตํด ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํ๋ซํผ์ ์ฌ์ฉ์์ ์ ์ค ์ผ์ด์ค๊ฐ ๋ช ํํ๊ณ ์ฌ์ฉ ํธ์์ฑ์ด ์ค์ํ๋ค๋ฉด ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํ์ง๋ง ์ดํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌ์ ๊ฐ์ด ์ ์ค์ผ์ด์ค๊ฐ ๋ค์ํ ๊ฒฝ์ฐ์๋ API ์๋ฒ ํ์ฅ์ ํตํด ์ ๊ณตํ๋ ๊ฒ์ด ๋ค์ํ ์ ์ค์ผ์ด์ค์ ๋์ํ๊ธฐ ์ข์ต๋๋ค. ๋ํ ํ์ฅ์ ๊ฒฝ์ฐ์๋ ์ฟ ๋ฒ๋คํฐ์ค ์ํ๊ณ์ ์กด์ฌํ๋ ๋ค์ํ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ฅ์ ๋ ์กด์ฌํฉ๋๋ค.
์ฟ ๋ฒ๋คํฐ์ค๋ฅผ ํ์ฅํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ด ์กด์ฌํฉ๋๋ค.
์ฌ์ด๋์นด ์ปจํ ์ด๋
์ฌ์ด๋์นด ์ปจํ ์ด๋๋ ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์ด๋์ ํจ๊ป ์คํ๋๋ ์ปจํ ์ด๋๋ก์จ ๋น์ฆ๋์ค ๋ก์ง์ด ์๋ ๋ณ๋์ ๋ก์ง์ ์ ๊ณตํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ๋๋ค. ์๋ฅผ ๋ค๋ฉด, ์ฌ์ด๋์นด ์ปจํ ์ด๋๋ฅผ ํตํด ๋ก๊ทธ๋ฅผ ์ ์กํ๊ฑฐ๋ ์๋น์ค ๋ฉ์ ํ๋ซํผ์์ ํ๋ก์ ๋คํธ์ํฌ๋ฅผ ๋ด๋นํ๋ ๊ฒ๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ
์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ ์ฟ ๋ฒ๋คํฐ์ค API ์์ฒญ์ด etcd์ ์ ์ฅ๋๊ธฐ ์ ์ ์ ํจ์ฑ ๊ฒ์ฆ๊ณผ ๊ฐ์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ํํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋๋ค.
CRD
CRD๋ ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ์ ์ฌ์ฉ์๊ฐ ์ ์ํ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. CRD๋ฅผ ์ฌ์ฉํ๋ฉด ๊ณ ์์ค์ ์ถ์ํ๋ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด Elasticsearch๋ผ๋ CRD๋ฅผ ์ ์ํ๋ฉด ์ด๋ฅผ ์์ฑํ๋ฉด ์๋์ผ๋ก Elasticsearch Cluster๋ฅผ ์์ฑํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. CRD์ ๊ด๋ จ๋ ๋ด์ฉ์ Operator SDK ๊ด๋ จ ๊ธ์ ํตํด ์์ธํ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ ์ฌ์ด๋์นด ์ปจํ ์ด๋๋ CRD๋ ๊ธฐ์กด์ ์ฌ์ฉํด๋ณธ์ ์ด ์์ง๋ง ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ์ ๋ํด์๋ ์ฒ์ ์ ํด๋ณด๋ ๋ด์ฉ์ด๊ธฐ ๋๋ฌธ์ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ์ ๋ํด ์์ธํ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ?
์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ API ์์ฒญ์ ๊ฐ๋ก์ฑ ํน์ ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ๋ฐฉ๋ฒ์ ์๋ฏธํฉ๋๋ค. ๋ฆฌ์์ค๋ฅผ ์ ์ํ์ง ์๊ฑฐ๋ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉ๋๋ StorageClass๊ฐ ๊ฒฐ์ ๋๋ ๊ฒ์ ๋ด๋ถ์๋ ๋ชจ๋ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์๋ ๊ทธ๋ฆผ์ ์ฟ ๋ฒ๋คํฐ์ค API๊ฐ etcd์ ์ ์ฅ๋๊ธฐ ์ ๊น์ง ํ๋ฆ์ ๋ํ๋ ๋๋ค.
์ด ๊ทธ๋ฆผ์์ ์ ์ ์๋ฏ์ด ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ API ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ณผ์ ์ค ํ ๋จ๊ณ์ด๋ฉฐ ์์ฒญ์ ๊ฒ์ฆํ๊ฑฐ๋ ๋ณ๊ฒฝํ๋ ์ญํ ์ ์ํํ ์ ์์ต๋๋ค. (๊ฒ์ฆ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ ์์ ํ ์ ์๋ ๋ฐ๋ฉด์ ๋ณ๊ฒฝ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ ์์ ํ ์ ์์ต๋๋ค.)
์ข ๋ฅ
์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ์๋ standard์ dynamic์ด๋ผ๋ 2๊ฐ์ง ๋ฑ๊ธ์ด ์กด์ฌํฉ๋๋ค. standard๋ API ์๋ฒ์ ํจ๊ป ์ปดํ์ผ๋๊ณ , API๊ฐ ์์๋ ๋ ์ค์ ํด์ผํ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์๋ฏธํฉ๋๋ค. dynamic๋ ๋ฐํ์ ์์ ์ ์ค์ ํ ์ ์๋ ์ปจํธ๋กค๋ฌ๋ก์จ ์ฟ ๋ฒ๋คํฐ์ค์ ์ธ๋ถ์์ ๊ฐ๋ฐ๋ฉ๋๋ค. (dynamic ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ HTTP ์ฝ๋ฐฑ์ ํตํด ์์ฒญ์ ๋ฐ๋ webhook์ด ์ ์ผํ๊ฒ ์กด์ฌํฉ๋๋ค.)
Standard
์ฟ ๋ฒ๋คํฐ์ค์๋ default๋ก ์ ๊ณต๋๋ standard ์ด๋๋ฏธ์
์ปจํธ๋กค๋ฌ๊ฐ ์กด์ฌํฉ๋๋ค. ๊ฐ๊ฐ์ ์ด๋๋ฏธ์
์ปจํธ๋กค๋ฌ๊ฐ ์ํํ๋ ์ญํ ์ ์ฟ ๋ฒ๋คํฐ์ค ๋ฌธ์์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
API ์๋ฒ์ `--enable-admission-plugins=<controller-name-1>,<controller-name-2>`์ ํํ๋ก ์ค์ ์ ์ถ๊ฐํจ์ผ๋ก์จ ์ํ๋ ์ด๋๋ฏธ์
์ปจํธ๋กค๋ฌ๋ฅผ ํ์ฑํํ ์ ์์ต๋๋ค.
Dynamic
์ฟ ๋ฒ๋คํฐ์ค์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ์ด์ธ์ ํน์ ํ ์ ์ค์ผ์ด์ค๋ฅผ ๋์ํ๊ธฐ ์ํ ์ด๋๋ฏธ์ ์ปจํธ๋กค๋ฌ๋ฅผ ์ ์ํ ์๋ ์์ต๋๋ค. ์ด ๋ ์ฌ์ฉ๋๋ ํ๋ฌ๊ทธ์ธ์ด MutatingAdmissionWebhook๊ณผ ValidatingAdmissionWebhook์ ๋๋ค. MutatiingAdmissionWebhook์ ์์ฒญ์ ๋ณ๊ฒฝ, ValidatingAdmissionWebhook์ ์์ฒญ์ ๊ฒ์ฆ์ ์ํํ๊ฒ ๋ฉ๋๋ค. ์์ ๊ทธ๋ฆผ์์์ฒ๋ผ webhook ๋ถ๋ถ์ ์ง์ ๊ฐ๋ฐํจ์ผ๋ก์จ ์ปค์คํ ํ ๋ณ๊ฒฝ, ๊ฒ์ฆ ๋ก์ง์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
Webhook ๋์ ๊ณผ์
๋จผ์ , WebHook์ด ๋์ํ๋ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. Mutating/ValidatingWebhookController๋ AdmissionRequest๋ฅผ webhook server์ POST๋ก ์์ฒญ์ ์ ์กํฉ๋๋ค.
- AdmissionRequest์๋ AdmissionReview๋ผ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ์ด ๊ฐ์ฒด๋ API server๊ฐ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฐ์ ๋ฉ๋ํ์คํธ๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด์ ๋๋ค.
2. Webhook Server๋ ์ํ๋ ๋ก์ง์ ์ํํ์ฌ ์์ฒญ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ฑฐ๋ ์์ฒญ์ ๋ณ๊ฒฝํ๊ณ ์ด์ ๋ํ ์๋ต์ AdmissionResponse ํํ๋ก ๋ณด๋ ๋๋ค.
- AdmissionResponse๋ webhook server์์ admission controller์๊ฒ ์์ฒญ์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด์ ๋๋ค. AdmissionResponse๋ UID, Allowed, Status์ ๊ฐ์ ํ๋๊ฐ ์กด์ฌํฉ๋๋ค. UID๋ webhook server๊ฐ ๋ฐ์ AdmissionReview์ ๋์ผํ UID๋ฅผ ๋ฐํํด์ค์ผํฉ๋๋ค. Allowed๋ ํด๋น ์์ฒญ์ ์น์ธํ ์ง, ๊ฑฐ์ ํ ์ง์ ๋ํ ํ์๋ก ์ด์ ๋ํ ์ํ๊ฐ์ผ๋ก Status๋ฅผ ๋๊ฒจ์ฃผ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค.
- Allowed๊ฐ True์ด๊ณ MutatingAdmissionController์ ๊ฒฝ์ฐ, webhook server๋ ์๋ณธ ์์ฒญ์ ์์ ํ์ฌ ์ ์กํ ์๋ ์์ต๋๋ค. ์ด ๋ ์์ ๋ ๋ถ๋ถ์ ์๋ ค์ฃผ๋ ๋ฐฉ๋ฒ์ผ๋ก ํ์ฌ Kubernetes๋ JSON patch ๋ฐฉ๋ฒ๋ง ์ง์ํฉ๋๋ค.
JSON Patch
๊ฐ๋ตํ๊ฒ JSON Patch ๋ฐฉ๋ฒ์ ๋ํด ์์๋ฅผ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ๋ง์ฝ, Deployment์ replicas์๊ฐ ์ง์ ๋์ด ์์ง ์์ ๊ฒฝ์ฐ, ๊ธฐ๋ณธ์ ์ผ๋ก 3์ด๋ผ๋ ๊ฐ์ ์ค์ ํด์ฃผ๋ ์ํฉ์ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค. ์ด ๋, ํด๋นํ๋ JSON patch๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
[{"op": "add", "path": "/spec/replicas", "value": 3}]
์ด JSON Patch๋ฅผ ์ ์กํ๊ธฐ ์ํด์๋ patchType์ผ๋ก JSONPatch๋ฅผ patch ๊ฐ์ผ๋ก ์์ JSON์ base64๋ก ์ธ์ฝ๋ฉํ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ค์ผ ํฉ๋๋ค. ์ต์ข ์ ์ผ๋ก ์์ฑ๋๋ Response๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "<value from request.uid>",
"allowed": true,
"patchType": "JSONPatch",
"patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
}
}
Custom Mutating Webhook ๊ฐ๋ฐ
์์ ์ค๋ช ์ ๊ธฐ๋ฐ์ผ๋ก ์ปค์คํ ํ mutating์ ์ํํ๋ webhook ์๋ฒ๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ์๋๋ฆฌ์ค๋ก๋ inject annotation์ด ์กด์ฌํ๋ deployment๊ฐ ์์ฑ๋ ๋, init container๋ฅผ injectํด์ฃผ๋ ๊ธฐ๋ฅ์ด ํ์ํ๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค.
์ธ์ฆ์ ๋ฐ๊ธ
Admission Controller๋ Webhook Server์ HTTPS๋ฅผ ํตํด ํต์ ํ๊ธฐ ๋๋ฌธ์, ๊ฐ์ฅ ๋จผ์ ํด์ผํ ์์ ์ Webhook Server์์ ํ์ํ ์ธ์ฆ์๋ฅผ ๋ฐ๊ธ๋ฐ๋ ์ผ์ ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ Common Name์ ๋ํ ์ค์ ์ ๋๋ค. alice_k106๋์ ๊ธ์ ์ฐธ๊ณ ํ๋ฉด ์ธ์ฆ์์ Common Name์ผ๋ก ์ฟ ๋ฒ๋คํฐ์ค ๋ด๋ถ DNS์์ ์ฌ์ฉ๋๋ ์ด๋ฆ์ ์ง์ ํด์ผ ํฉ๋๋ค. ์ ๊ฐ ์์ฑํ ์๋น์ค์ ์ด๋ฆ์ mutate-server-svc, ๋ค์์คํ์ด์ค๋ mutate-webhook์ด๊ธฐ ๋๋ฌธ์ ์ต์ข ์ ์ผ๋ก mutate-server-svc.mutate-webhook.svc๋ผ๋ ์ด๋ฆ์ผ๋ก CN์ ์ค์ ํด์คฌ์ต๋๋ค.
โ mkdir certsopenssl
โ req -nodes -new -x509 -keyout certs/ca.key -out certs/ca.crt -subj "/CN=Admission Controller Demo"
โ openssl genrsa -out certs/admission-tls.key 2048
โ openssl req -new -key certs/admission-tls.key -subj "/CN=mutate-server-svc.mutate-webhook.svc" | openssl x509 -req -CA certs/ca.crt -CAkey certs/ca.key -CAcreateserial -out certs/admission-tls.crt
TLS Secret ์์ฑ
๋ค์์ผ๋ก ์์์ ๋ฐ๊ธ๋ฐ์ ์ธ์ฆ์๋ฅผ Mutate Webhook Server์์ ์ฌ์ฉํ๊ธฐ ์ํด TLS Secret์ ์์ฑํด์ค๋๋ค.
โ kubectl create -n mutate-webhook secret tls admission-tls \ --cert "certs/admission-tls.crt" \ --key "certs/admission-tls.key"
Mutate Webhook Server
์ ๊ฐ ์ํํ Mutate ๋ก์ง์ Deployment์ initContainer ํ๋์ ์ฌ์ ์ ์ ์ํ ๋ฉ๋ํ์คํธ๋ฅผ ์ถ๊ฐํ๋ ๋ก์ง์ ๋๋ค. github.com/morvencao/kube-mutating-webhook-tutorial ์ ์ฐธ๊ณ ํด ์ ๊ฐ ํ์ํ ๋ก์ง์ผ๋ก ์์ ํ์ฌ ๊ตฌ์ถํ Webhook Server๋ Github์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
๊ฐ๋จํ๊ฒ ์ค๋ช ํ๋ฉด ๋จผ์ AdmissionReview ๊ฐ์ฒด๋ฅผ ๋ฐ์ Deployment์ ๋ํ ์ ๋ณด๋ฅผ ์ป์ด์ต๋๋ค.
func (ws WebhookServer) mutate(admissionReview *admissionv1.AdmissionReview) *admissionv1.AdmissionResponse {
request := admissionReview.Request
var deployment appv1.Deployment
if err := json.Unmarshal(request.Object.Raw, &deployment); err != nil {
log.Errorf("Couldn't unmarshall raw object : %v", err)
return &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Message: err.Error(),
},
}
}
....
ํด๋น Deployment์ ๋ํด Mutation ๋์(Init Container๋ฅผ ์ถ๊ฐํ ๋์)์ธ์ง ํ๋จํฉ๋๋ค. ์ ๋ init-container-injector-webhook.sphong.com/inject = "true" ์ด๋ ธํ ์ด์ ์ ํตํด Mutation ๋์์ ์ ์ ํ์์ต๋๋ค.
func isMutationTarget(ignoreNamespaces []string, metadata *metav1.ObjectMeta) bool {
...
annotation := metadata.GetAnnotations()
if annotation == nil {
annotation = make(map[string]string)
}
status := annotation[admissionWebhookAnnotationInjectKey]
if strings.ToLower(status) == "true" {
return true
}
return false
}
Mutataion Target์ธ ๊ฒฝ์ฐ, init container ํ๋์ ๊ธฐ์กด์ ์ ์ํ ๋ฉ๋ํ์คํธ๋ฅผ ์ถ๊ฐํด์ค๋๋ค. ๋ํ, ๋ค์๋ฒ๋ถํฐ mutation์ ๋์์ด ๋์ง ์๋๋ก init-container-injector-webhook.sphong.com/inject = "injected"๋ก ์ ๋ฐ์ดํธํฉ๋๋ค. ์์์ ์ธ๊ธํ๋ ๊ฒ์ฒ๋ผ ์ด๋ฐ ์ถ๊ฐ, ์ ๋ฐ์ดํธ์ ๋ํ ์ ๋ณด๋ JSON Patch๋ฅผ ํตํด ์ ๋ฌํฉ๋๋ค.
func createPatch(deployment *appv1.Deployment, config *Config, annotations map[string]string) ([]byte, error) {
var patch []patchOperation
patch = append(patch, addInitContainer(deployment.Spec.Template.Spec.InitContainers, config.Containers, "/spec/template/spec/initContainers")...)
patch = append(patch, updateAnnotation(deployment.Annotations, annotations)...)
return json.Marshal(patch)
}
์ต์ข ์ ์ผ๋ก AdmissionReview๊ฐ์ฒด๋ฅผ ์์ฑํด์ ์๋ต์ Admission Controller์๊ฒ ์ ์กํฉ๋๋ค.
func (ws WebhookServer) Serve(responseWriter http.ResponseWriter, request *http.Request) {
...
// ์๋ต์ ๋ด์ ๊ฐ์ฒด
var admissionResponse *admissionv1.AdmissionResponse
// Webhook Server๊ฐ ๋ฐ์ AdmissionReview ๊ฐ์ฒด (์๋ณธ)
originAdmissionReview := admissionv1.AdmissionReview{}
// Deserializer
if _, _, err := deserializer.Decode(requestBody, nil, &originAdmissionReview); err != nil {
log.Errorf("Can't decode request body: %v", err)
admissionResponse = &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Message: err.Error(),
},
}
} else {
// Mutate Login ์ํ
admissionResponse = ws.mutate(&originAdmissionReview)
}
// Admission Review ๊ฐ์ฒด์ TypeMeta ํ๋๊ฐ Required์ด๊ธฐ ๋๋ฌธ์ ๋ช
์์ ์ผ๋ก ์ ์ํด์ค์ผ ํ๋ค.
typeMeta := metav1.TypeMeta{
Kind: "AdmissionReview",
APIVersion: "admission.k8s.io/v1",
}
// ์๋ต์ ์ํ AdmissionReview ๊ฐ์ฒด
mutatedAdmissionReview := admissionv1.AdmissionReview{TypeMeta: typeMeta}
mutatedAdmissionReview.Response = admissionResponse
// UID๋ Request AdmissionReview ๊ฐ์ฒด์ UID์ ๋์ผ
if originAdmissionReview.Request != nil {
mutatedAdmissionReview.Response.UID = originAdmissionReview.Request.UID
}
// return json response
data, err := json.Marshal(mutatedAdmissionReview)
if _, err := responseWriter.Write(data); err != nil {
log.Errorf("Can't Write Response : %v", err)
http.Error(responseWriter, fmt.Sprintf("Can't write response : %v", err), http.StatusInternalServerError)
}
...
Webhook Server Deployment
ํด๋น ์๋ฒ์ ๋ํด Deployment์ Service๋ฅผ ์์ฑํฉ๋๋ค. ์ด ๋, ์์ ์์ฑํ tls ์ํฌ๋ฆฟ๊ณผ init container์ ๋ํ ์ค์ ์ ๋ง์ดํธ ํด์ค๋๋ค.
Deployment
Service
Mutate Webhook Configuration
๋ค์์ผ๋ก Mutate Webhook์ ๋ํ ConfigMap์ ์์ฑํฉ๋๋ค. ์ด ์ค์ ์ ํตํด mutate server์ ๋ํ ์ฐ๊ฒฐ ์ ๋ณด์ caBundle, ์ธ์ mutate webhook์ด ์คํ๋ ์ง์ ๋ํด ์ ์ํ ์ ์์ต๋๋ค.
์์์ ์์ฑํ ca.crt๋ฅผ ํตํด CA_BUNDLE ๊ฐ์ ์ฑ์์ฃผ๊ณ ConfigMap์ ์์ฑํ๋ฉด ์์ผ๋ก Deployment๋ฅผ ์์ฑํ ๋๋ง๋ค Mutate ๋ก์ง์ ์ํํ๊ฒ ๋ฉ๋๋ค.
โ export CA_BUNDLE=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.ca\.crt}")
โ export CA_BUNDLE=$(cat certs/ca.crt | base64 | tr -d '\n')
โ cat deploy/webhook-config.yaml | sed "s|\${CA_BUNDLE}|${CA_BUNDLE}|g" | kubectl apply -n mutate-webhook -f -
์ต์ข ์ ์ผ๋ก ์๋์ Deployment๋ฅผ ์์ฑํด MutatingWebhook์ด ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
ํ์ธํด๋ณด๋ฉด nginx-deployment์ ์ํ๋ Pod๋ค์ Init Container ์ค์ ์ด ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฒ๊ธ์์๋ ์ฟ ๋ฒ๋คํฐ์ค์์ ๊ณ ์์ค์ ์ถ์ํ๋ฅผ ์ ๊ณตํ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋์ธ Admission Controller์ ๋ํด์ ์์๋ณด์์ต๋๋ค. ์ฌ์ฉ๋ ๋ชจ๋ ์ฝ๋๋ Github์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
์ฐธ๊ณ ์๋ฃ
- kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/
- kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
'๐ Kubernetes' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Kubernetes ๋ด๋ถ ๊ตฌ์กฐ ์ดํดํ๊ธฐ] 1. ์ฟ ๋ฒ๋คํฐ์ค ํด๋ฌ์คํฐ ๊ตฌ์ฑ ์์ (0) | 2021.04.12 |
---|---|
Pinpoint Agent Helm Chart ์์ฑํ๊ธฐ (0) | 2021.03.06 |
Elasticsearch Operator ๊ฐ๋ฐํ๊ธฐ (0) | 2020.12.18 |
Kubernetes Operator (feat. Operator SDK) (0) | 2020.12.18 |
Argo Project๋ฅผ ์ฌ์ฉํ์ฌ CI/CD ๊ตฌ์ถํ๊ธฐ (0) | 2020.12.18 |
๋๊ธ