Istio Circular Virtual Service
์ค๋์ ์ฃผ์ ๋ ๊ผฌ๋ฆฌ์ ๊ผฌ๋ฆฌ๋ฅผ ๋ฌด๋, ๋ฌดํ๋ฒ ํธ์ถ์ด๋ค!
Istio์ VirtualService
์ ๋์์ ์ดํดํ๋ ค๊ณ ํ ๋, ์ดํด๊ฐ ์ ๋๋๊ฒ spec.hosts
์๋ host ์ฃผ์๋ฅผ ์ ๊ณ , destination
์์ฑ์๋ host ์ฃผ์๋ฅผ ์ ๋ ๊ฑฐ ์๋ค.
๊ทธ๋ฐ ๋์๊ฒ ์ด๋ฐ ์ง๋ฌธ์ด ๋ ์ฌ๋๋๋ฐโฆ
- โ๋ง์ฝ ์๊ธฐ ์์ ์ destination์ผ๋ก ๊ฐ๋ VirtualService๋ฅผ ๋์ฐ๋ฉด, ์ด VirtualService๋ ๋ฌดํ๋ฒ evaluation ๋๋ ๊ฑธ๊น?โ
- โ๋ง์ฝ VirtualService๋ก host A์ ํธ๋ํฝ์ host B๋ก ๋ณด๋ด๊ณ , ๋ ๋ค๋ฅธ VirtualService๋ก๋ host B๋ ๋ค์ host A๋ก ํธ๋ํฝ์ ๋ณด๋ธ๋ค๋ฉด, ์ด ๊ฒฝ์ฐ๋ evaluation์ด ๋ฌดํ๋ฒ ๋๋ ๊ฑธ๊น?โ
๋ญ๊ฐ โ๋ฌดํ๋ฒโ evaluation ๋๋ ๊ฒ์ ๋ํ ๊ถ๊ธ์ฆ์ด ์๊ฒผ๊ณ , ์ง์ ํด๋น ์ผ์ด์ค๋ค์ ํด๋ฌ์คํฐ์ ๋์ ์คํํด๋ณด์๋ค!
๋ค์ helloworld ์์ ๋ฅผ ๋์ฐ์
$ kubectl apply -n default -f https://raw.githubusercontent.com/istio/istio/1.20.2/samples/helloworld/helloworld.yaml
service/helloworld created
deployment.apps/helloworld-v1 created
deployment.apps/helloworld-v2 created
๊ทธ๋ฐ๋ฐ svc/helloworld
๊ฐ ์์ผ๋ ํธ๋ํฝ ๋ถ์ฐ์ด ๋ญ๊ฐ ์ ์ ๋๋ ๊ฒ ๊ฐ์์ svc/helloworld
๋ ์ง์๋์!!
$ kubectl delete svc/helloworld
ํ๊ณ v1
, v2
๋ฒ์ ์ API call์ ๋ณด๋ผ ์ ์๋๋ก ๊ฐ๊ฐ์ K8s Service ๋ฆฌ์์ค๋ฅผ ๋ง๋ค์ด๋์.
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: helloworld-v1
labels:
app: helloworld
service: helloworld
version: v1
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
version: v1
---
apiVersion: v1
kind: Service
metadata:
name: helloworld-v2
labels:
app: helloworld
service: helloworld
version: v2
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
version: v2
EOF
์, ๊ทธ๋ฆฌ๊ณ helloworld v1
, v2
์ ํธ๋ํฝ์ ํ๋ ค๋ณด๋ผ ํ
์คํธ์ฉ nginx
Pod๋ ํ๋ ๋์ฐ์.
$ k run nginx --image=nginx
$ k exec -it nginx -- sh
# <on some pod>
while true; do curl "http://helloworld.default:5000/hello"; done
์ข์์ด!! ์ค๋น๋ ๋๋ฌ๋ค!! ๏ผยดโ`๏ผ๏ฝ
๋ฌดํ Evaluation์ด ์ผ์ด๋ ์ง ์คํ
์๊ธฐ ์์ ์ผ๋ก ๋ผ์ฐํ ํ๋ Virtual Service
โ๋ง์ฝ ์๊ธฐ ์์ ์ destination์ผ๋ก ํ๋ VirtualService๋ฅผ ๋์ฐ๋ฉด, ์ด VirtualService๋ ๋ฌดํ๋ฒ evaluation ๋๋ ๊ฑธ๊น?โ
# self-destination.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: self-destination
spec:
hosts:
- "helloworld-v1.default.svc.cluster.local"
http:
- route:
- destination:
host: helloworld-v1.default.svc.cluster.local
์๋ฐ VirtualService๋ฅผ ๋ง๋ค๊ณ , nginx
Pod์ ์ ์ํด์ ํธ๋ํฝ์ ํ๋ ค๋ณด์.
$ k exec -it nginx -- sh
# <on some pod>
while true; do curl "http://helloworld-v1.default.svc.cluster.local:5000/hello"; done
ํ์โฆ?
๋ง์ฝ ๋ฌดํ๋ฒ Evaluation์ด ์ผ์ด๋ฌ๋ค๋ฉด, timeout์ด ๋ฐ์ํ์ ๊ฒ ๊ฐ์๋ฐ, ์๊ธฐ ์์ ์ผ๋ก ํธ๋ํฝ์ด ์ ๊ฐ๊ณ ์๋ค!!
์๋ก์๊ฒ ํธ๋ํฝ์ ๋ณด๋ด ๋ฒ๋ฆฌ๋ Virtual Service
์๋ก ํธ๋ํฝ์ ๋ฏธ๋ฃจ๋ VirtualService
๋ฅผ ๊ตฌ์ฑํด๋ณด์.
# circular-traffic-shift.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: traffic-shift-v1-to-v2
spec:
hosts:
- "helloworld-v1.default.svc.cluster.local"
http:
- route:
- destination:
host: helloworld-v2.default.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: traffic-shift-v2-to-v1
spec:
hosts:
- "helloworld-v2.default.svc.cluster.local"
http:
- route:
- destination:
host: helloworld-v1.default.svc.cluster.local
๋ญ๊ฐ ์์ํ๊ธฐ๋ก๋ v1
์ด๋ v2
๊ฐ ๋ฒ๊ฐ์ ๊ฐ๋ฉด์ ๋์ฌ ์ค ์์๋๋ฐ, vs/traffic-shift-v1-to-v2
์ ๋ช
์ํ ๋๋ก ํธ๋ํฝ์ด ์ค์ง v2
๋ก๋ง ์ ๊ฐ๊ณ ์๋ค!!
๊ฒฐ๋ก
๋ฌดํ๋ฒ Evaluation์ด ์ผ์ด๋์ง ์๋ ์ด์ ๋, Envoy Proxy๊ฐ ๋์ํ๋ ๋ฐฉ์์ ์๋ค.
์ผ๋จ Envoy Proxy๋ ์ฑ์์ in/out ํ๋ ํธ๋ํฝ์ ๋์ ์ปจํธ๋กค ํ๋ ๋
์์ด๋ค. ๊ทธ๋์ nginx
๊ฐ helloworld-v2.default
์ ์์ฒญ์ ๋ณด๋ธ๋ค๋ฉด, ํ์ฌ Service Mesh์ ์ ์๋ VirtualService
์ค์ ์ ๊ณณ์ hosts
๋ก ๊ฐ๋ VirtualService
๋ฅผ ์ฐพ์ ํ, ๊ทธ ViritualService
์ ๊ท์น์ ์ ์ฉํ๋ค.
์ด๋, Envoy Proxy๊ฐ ํธ๋ํฝ์ helloworld-v1.default
๋ก ๋ณด๋ด๋ผ๊ณ ์ ํ์ผ๋ฉด ์ถ๊ฐ์ ์ธ evaluation์ ๋์ด์ ์๋ค! ์ฆ, ๋ค์ helloworld-v1.default
๋ฅผ hosts
๋ก ๊ฐ๋ VirtualService
๋ฅผ ์ฐพ์ง๋ ์๋๋ค๋ ๊ฒ์ด๋ค.
๋๊ฐ๋ ํธ๋ํฝ์๋ VirtualService ๊ท์น์ ์ ์ฉ
์ด๋ป๊ฒ ๋ณด๋ฉด ๋ด๊ฐ ์ฐฉ๊ฐํ ๋ถ๋ถ์ VirtualService
๊ฐ evaluation ๋๋ ์ง์ ์ด ํธ๋ํฝ์ด ๋๋ฌํ๋ Pod์ Envoy Proxy๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ธ ๊ฒ ๊ฐ๋ค. ๊ทธ๋ฌ๋ ์ค์ ๋ก ๊ทธ ๊ณผ์ ์ด ํธ๋ํฝ์ ๋ณด๋ด๋ Pod์ Envoy Proxy์์ ์งํ ๋์๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ VirtualService
์๋ Istio Service Mesh ์ธ๋ถ์ host๋ค๋ hosts
์ destination
์ ์ ์ ์ ์๋ค.
naver.com
์ผ๋ก ๊ฐ๋ ํธ๋ํฝ์ ์ธ๋ถ๊ฐ ์๋๋ผ ๋ด๋ถ์ ๋ค๋ฅธ Pod์ผ๋ก ๋ณด๋ด๋ฒ๋ฆฐ๋ค๊ฑฐ๋ ๋ฏธ๋ฌ๋ง ํ๋๋ก VirtualService
๋ก ์ค์ ํ ์ ์๋ค.
๋, VirtualService
๊ท์น์ Envoy Proxy๊ฐ ์๋ Pod์์๋ ์ ์ฉ๋์ง ์๋ ์ ๋ VirtualService
์ ๊ท์น์ด ํธ๋ํฝ์ ๋ณด๋ด๋ Pod์ Envoy Proxy์์ ์ผ์ด๋๊ธฐ ๋๋ฌธ์ด๋ค.
๋ค์ด์ค๋ ํธ๋ํฝ์๋ DestinationRule ๊ท์น์ ์ ์ฉ
๋ฐ๋๋ก ํธ๋ํฝ์ด ๋๋ฌํ๋ Pod์ Envoy Proxy์์๋ DestinationRule
์ evaluation์ด ์ผ์ด๋๋ค!!
์๋ฅผ ๋ค์ด,
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld-v1-max-connection
spec:
host: helloworld-v1.default.svc.cluster.local
trafficPolicy:
connectionPool:
http:
http2MaxRequests: 1
์๋ ๊ฒ DestinationRule
์ ์ค์ ํ๋ฉด, ์ค์ง ํ๋ฒ์ ํ๋์ http request๋ง ํ์ฉํ๋๋ก ์ ์ฉํด๋ณด์.
์๋ ๊ฒ ํ๋ฉด, nginx
Pod์ ์ ์ํ๋ ํฐ๋ฏธ๋ 2๊ฐ๋ฅผ ์ด์ด์ ์๋ ์์ฒญ์ ๋ณด๋ด๋ฉด ์ด๋ฐ ํ์์ ๋ณผ ์ ์๋ค.
$ while true; do curl "http://helloworld-v2.default.svc.cluster.local:5000/hello"; done
(DR ์ค์ ์ helloworld-v1.default
์ ํ๋๋ฐ, ์์์ VS ์ค์ ํ๊ฒ ์์ด์ helloworld-v2.default
์ ์์ฒญ์ ๋ณด๋ธ๋ค!!)
์ ์ ๋ณด์ด๋ ํ๋ ํด์ ๋ณด์
์บก์ณ๋ฅผ ๋ณด๋ฉด ์ฒ์์๋ v1
์ผ๋ก ์์ฒญ์ด ์ ๊ฐ๋ค๊ฐ, ๋ค๋ฅธ ํฐ๋ฏธ๋์์๋ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์์ํ๋ฉด์ reset reason: overflowupstream connect error or disconnect/reset before headers
์๋ฌ๋ฅผ ๋ฐ๊ฒ ๋๋ค.
์ ๊ธฐํ ์ ์ ๋ถ๋ช
์์ฒญ์ helloworld-v2
๋ก ๋ณด๋๋๋ฐ, helloworld-v1
์ DR ๋ฃฐ์ ์ํด upstream overflow๊ฐ ๋ฐ์ ํ๋ค๋ ๊ฒ์ด๋ค.
๋, ๋ง์ฝ Istio Service Mesh ๋ฐ๊นฅ์ Pod์ด DR์ด ์ค์ ๋ helloworld-v1.default
์ ์์ฒญ์ ๋ณด๋ด๋, ๋๊ฐ์ด ์ด max http request์ ๊ท์น์ ์ ์ฉ ๋ฐ๋ ๊ฒ์ด๋ค!! ์ด ๋ํ DestinationRule
์ด ํธ๋ํฝ์ ๋ฐ๋ ์ชฝ์ Envoy Proxy์์ ์ ์ฉ ๋๊ธฐ ๋๋ฌธ์ด๋ค!
์ฆ, ์ด ๊ฒฝ์ฐ ํธ๋ํฝ์ ๋ฐ๋ ์ชฝ์ DestinationRule
์ด ์ ์ฉ๋ ๊ฑฐ๋ผ๊ณ ๋ณผ ์ ์๋ค.