Istio+Kiali๋ฅผ ์ฌ์ฉํ์ฌ Canary ๋ฐฐํฌ ์์ ๋ฐ ์๊ฐํ
์ด ์๋ฆฌ์ฆ์ ๊ธฐ์ฌ
Kubernetes #1์ ์นด๋๋ฆฌ์ ๋ฐฐํฌ: Gitlab CI Kubernetes์ ์นด๋๋ฆฌ์ ๋ฐฐํฌ #2: Argo ๋กค์์ - (์ด ๊ธฐ์ฌ)
- Jenkins-X Istio Flagger๋ฅผ ์ฌ์ฉํ ์นด๋๋ฆฌ์ ๋ฐฐํฌ
์นด๋๋ฆฌ์ ๋ฐฐํฌ
์ฐ๋ฆฌ๋ ๋น์ ์ด ์ฝ๊ธฐ๋ฅผ ๋ฐ๋๋๋ค
์ด์ค ํฐ์ค
๊ทธ๋ฆฌ๊ณ ์ด ๊ธฐ์ฌ๋ฅผ ์ฝ์ผ๋ฉด Istio๊ฐ ๋ฌด์์ธ์ง ์ด๋ฏธ ์๊ณ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด ๊ทธ๊ฒ์ ๋ํด ์ฝ์ ์ ์์ต๋๋ค.
ํ ์คํธ ์ ์ฒญ
๊ฐ ํฌ๋์๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ istio-proxy๋ผ๋ ๋ ๊ฐ์ ์ปจํ ์ด๋๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
frontend-nginx ๋ฐ ๋ฐฑ์๋ Python Pod์ ํจ๊ป ๊ฐ๋จํ ํ ์คํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉํฉ๋๋ค. nginx ํฌ๋๋ ๊ฐ ์์ฒญ์ ๋ฐฑ์๋ ํฌ๋๋ก ๋ฆฌ๋๋ ์ ํ๊ณ ํ๋ก์๋ก ์๋ํฉ๋๋ค. ์ธ๋ถ์ ๋ณด๋ ๋ค์ yaml์์ ํ์ธํ ์ ์์ต๋๋ค.
ํ ์คํธ ์ ํ๋ฆฌ์ผ์ด์ ์ง์ ์คํ
๋ด ์๋ฅผ ๋ฐ๋ผ ์ด ํ
์คํธ ์ ํ๋ฆฌ์ผ์ด์
์ ์ง์ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์์ ์ฐธ์กฐํ์ธ์.
์ด๊ธฐ ๋ฐฐํฌ
์ฒซ ๋ฒ์งธ ๋ฐฐํฌ๋ฅผ ์์ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ํฌ๋์ ์ปจํ ์ด๋๊ฐ 2๊ฐ๋ง ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ฆ, Istio ์ฌ์ด๋์นด๊ฐ ์ด์ ๋ง ๊ตฌํ๋๊ณ ์๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์์คํ์ด์ค์ Istio Gateway Loadbalancer๋ ํ์๋ฉ๋๋ค. istio-system
:
ํธ๋ํฝ ์์ฑ
๋ค์ IP๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ฐํธ์๋ ํฌ๋์์ ์์ ํ๊ณ ๋ฐฑ์๋ ํฌ๋๋ก ์ ๋ฌํ ํธ๋ํฝ์ ์์ฑํฉ๋๋ค.
while true; do curl -s --resolve 'frontend.istio-test:80:35.242.202.152' frontend.istio-test; sleep 0.1; done
์ฐ๋ฆฌ๋ ๋ํ ์ถ๊ฐํ ๊ฒ์
๋๋ค frontend.istio-test
ํธ์คํธ ํ์ผ์.
Kiali๋ฅผ ํตํด ๋ฉ์ ๋ณด๊ธฐ
Tracing, Grafana, Prometheus ๋ฐ Kiali์ ํจ๊ป ํ
์คํธ ์ ํ๋ฆฌ์ผ์ด์
๊ณผ Istio๋ฅผ ์ค์นํ์ต๋๋ค(์์ธํ ๋ด์ฉ์ ์๋ ์ฐธ์กฐ).
istioctl dashboard kiali # admin:admin
Kiali๋ ๋ฉ์๋ฅผ ํตํด ํ์ฌ ํธ๋ํฝ์ ์๊ฐํํฉ๋๋ค.
๋ณด์๋ค์ํผ ํธ๋ํฝ์ 100%๊ฐ ํ๋ฐํธ์๋ ์๋น์ค๋ก ์ด๋ํ ๋ค์ v1 ๋ผ๋ฒจ์ด ์๋ ํ๋ฐํธ์๋ ํฌ๋๋ก ์ด๋ํฉ๋๋ค. ์์ฒญ์ ๋ฐฑ์๋ ์๋น์ค๋ก ๋ฆฌ๋๋ ์ ํ๊ณ ๋ค์ ๋ฐฑ์๋ ํฌ๋๋ก ๋ฆฌ๋๋ ์ ํ๋ ๊ฐ๋จํ nginx ํ๋ก์๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. v1์ด๋ผ๋ ๋ผ๋ฒจ์ ์ฌ์ฉํ์ธ์.
Kiali๋ Istio์ ์ ์๋ํ๋ฉฐ ๋ฐ์คํ ๋ฉ์ ๋ ๋๋ง ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค. ์ ๋ง ์ข์์.
์นด๋๋ฆฌ์ ๋ฐฐํฌ
์ฐ๋ฆฌ ๋ฐฑ์๋์๋ ์ด๋ฏธ ๋ ๊ฐ์ k8s ๋ฐฐํฌ๊ฐ ์์ต๋๋ค. ํ๋๋ v1์ฉ์ด๊ณ ๋ค๋ฅธ ํ๋๋ v2์ฉ์ ๋๋ค. ์ด์ Istio์๊ฒ ํน์ ๋น์จ์ ์์ฒญ์ v2๋ก ์ ๋ฌํ๋๋ก ์ง์ํ๋ฉด ๋ฉ๋๋ค.
1๋จ๊ณ: 10%
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ ์ผ์ VirtualService์ ๊ฐ์ค์น๋ฅผ ์กฐ์ ํ๋ ๊ฒ๋ฟ์
๋๋ค.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10
์์ฒญ์ 10%๊ฐ v2๋ก ๋ฆฌ๋๋ ์ ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
2๋จ๊ณ: 50%
์ด์ 50%๊น์ง๋ง ๋๋ฆฌ๋ฉด ์ถฉ๋ถํฉ๋๋ค.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
...
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 50
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 50
3๋จ๊ณ: 100%
์ด์ Canary ๋ฐฐํฌ๊ฐ ์๋ฃ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋ ์ ์์ผ๋ฉฐ ๋ชจ๋ ํธ๋ํฝ์ด v2๋ก ๋ฆฌ๋๋ ์ ๋ฉ๋๋ค.
์นด๋๋ฆฌ์๋ฅผ ์๋์ผ๋ก ํ ์คํธํ๊ธฐ
์ด์ ๋ชจ๋ ์์ฒญ์ 2%๋ฅผ v10 ๋ฐฑ์๋๋ก ๋ณด๋ธ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. v2๋ฅผ ์๋์ผ๋ก ํ ์คํธํ์ฌ ๋ชจ๋ ๊ฒ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น?
HTTP ํค๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํน๋ณํ ์ผ์น ๊ท์น์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- headers:
canary:
exact: "canary-tester"
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10
์ด์ ์ปฌ์ ์ฌ์ฉํ์ฌ ํค๋๋ฅผ ์ ์กํ์ฌ v2 ์์ฒญ์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
ํค๋๊ฐ ์๋ ์์ฒญ์ ์ฌ์ ํ โโ1/10 ๋น์จ๋ก ๊ตฌ๋๋ฉ๋๋ค.
๋ ๊ฐ์ง ์ข ์ ๋ฒ์ ์ ๋ํ ์นด๋๋ฆฌ์
์ด์ ํ๋ฐํธ์๋์ ๋ฐฑ์๋ ๋ชจ๋์ ๋ํด ๋ฒ์ v2๊ฐ ์๋ ์ต์ ์ ๊ณ ๋ คํด ๋ณด๊ฒ ์ต๋๋ค. ๋ ๊ฒฝ์ฐ ๋ชจ๋ ํธ๋ํฝ์ 10%๊ฐ v2๋ก ์ด๋ํ๋๋ก ์ง์ ํ์ต๋๋ค.
ํ๋ฐํธ์๋ v1๊ณผ v2๋ ๋ชจ๋ ๋ฐฑ์๋ v1๊ณผ v10์ ๋ํด 1/2์ ๋น์จ๋ก ํธ๋ํฝ์ ์ ๋ฌํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
v2๊ณผ ํธํ๋์ง ์๊ธฐ ๋๋ฌธ์ frontend-v2์ ํธ๋ํฝ์ backend-v1๋ก๋ง ์ ๋ฌํด์ผ ํ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น? ์ด๋ฅผ ์ํด ํ์์ ํตํด backend-v1์ ๋๋ฌํ๋ ํธ๋ํฝ์ ์ ์ดํ๋ โโํ๋ฐํธ์๋์ 10/2 ๋น์จ์ ์ค์ ํฉ๋๋ค. sourceLabels
:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
...
- match:
- sourceLabels:
app: frontend
version: v2
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100
๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๋ ํ์ํ ๊ฒ์ ์ป์ต๋๋ค.
์๋ Canary ์ ๊ทผ ๋ฐฉ์๊ณผ์ ์ฐจ์ด์
ะ ์ฒซ ๋ฒ์งธ ๋ถ๋ถ ๋ ๊ฐ์ k8s ๋ฐฐํฌ๋ฅผ ์ฌ์ฉํ์ฌ Canary ๋ฐฐํฌ๋ฅผ ์๋์ผ๋ก ์ํํ์ต๋๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ๋ณต์ ๋ณธ ์๋ฅผ ๋ณ๊ฒฝํ์ฌ ์์ฒญ ๋น์จ์ ์ ์ดํ์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ํจ๊ณผ์ ์ด์ง๋ง ์ฌ๊ฐํ ๋จ์ ์ด ์์ต๋๋ค.
Istio๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์ ๋ณธ ์์ ๊ด๊ณ์์ด ์์ฒญ ๋น์จ์ ๊ฒฐ์ ํ ์ ์์ต๋๋ค. ์ด๋ ์๋ฅผ ๋ค์ด HPA(Horizontal Pod Autoscalers)๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ Canary ๋ฐฐํฌ์ ํ์ฌ ์ํ์ ๋ฐ๋ผ ๊ตฌ์ฑํ ํ์๊ฐ ์์์ ์๋ฏธํฉ๋๋ค.
ํฉ๊ณ
Istio๋ ํ๋ฅญํ๊ฒ ์๋ํ๋ฉฐ Kiali์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋งค์ฐ ๊ฐ๋ ฅํ ์กฐํฉ์ด ๋ฉ๋๋ค. ๋ค์ ๊ด์ฌ ๋ชฉ๋ก์ ์๋ํ ๋ฐ Canary ๋ถ์์ ์ํด Spinnaker์ Istio๋ฅผ ๊ฒฐํฉํ๋ ๊ฒ์ ๋๋ค.
์ถ์ฒ : habr.com