Istio โhelloworldโ ๋ฐ๋ชจ
์ด๋ฒ ํฌ์คํธ์์๋ Istio์์ ์ ๊ณตํ๋ helloworld ์์ ๋ฅผ ํ์ฉํด Istio์ Virtual Service์ Destination Rule์ ๊ธฐ๋ฅ๋ค์ ์ง์ ์คํํด๋ณธ๋ค. ๐งช
์ฌ์ ์ค๋น
์ผ๋จ hello ์์ ๋ฅผ ๋์ธ ๋ค์์คํ์ด์ค์ label์ ๋ถ์ฌํด์ envoy sidecar๊ฐ ๋ถ์ ์ ์๋๋ก ๋ง๋ค์.
kubectl label ns default istio-injection=enabled
๊ทธ๋ฆฌ๊ณ ์์ ํฌ์คํธ๋ฅผ ์ฐธ๊ณ ํด Istio์ Kiali, Prometheus Addon์ ์ค์นํ๋ค.
โก๏ธ Install Istio and Addons(Prometheus, Kiali)
helloworld ์ดํ๋ฆฌ์ผ์ด์
istio์ ์์ ์ค ๊ฐ์ฅ ์ฌํํ ๋
์์ผ๋ก /hello ์๋ํฌ์ธํธ์ ์์ฒญ์ ๋ณด๋ด๋ฉด, ์์ ์ ๋ฒ์ ์ ๋ณด๋ฅผ ๋ฆฌํดํ๋ค.
$ curl -X GET localhost:5000/hello
Hello version: v1, instance: helloworld-v1-867747c89-n6sl2
์ฐ์ ์ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌํด๋ณด์!
$ kubectl apply -n default -f https://raw.githubusercontent.com/istio/istio/1.26.1/samples/helloworld/helloworld.yaml
service/helloworld created
deployment.apps/helloworld-v1 created
deployment.apps/helloworld-v2 created
๊ทธ๋ฌ๋ฉด, ๋ฒ์ v1, v2์ helloworld ์ดํ๋ฆฌ์ผ์ด์
์ด ๋ฐฐํฌ๋๋ค.
์ง๊ธ ๋ง๋ค์ด์ง service/helloworld๋ v1, v2๋ฅผ round robin์ผ๋ก ํธ๋ํฝ์ ๋ถ์ฐํ๋ค.
ํ ์คํธ๋ฅผ ์ํด ์๋ ๋ช ๋ น์ด๋ก ์์ Pod์ ๋์์ ํธ๋ํฝ ๋ผ์ฐํ ์ด ์ด๋ป๊ฒ ๋๋์ง ํ์ธํด๋ณด์. (์ด๋, k port-forwardํ ๊ฑธ๋ก ์ ์ํ๋ฉด ์ ๋๋ค. ๊ทธ ์ด์ ๋ ์ ๊นํ ์ด์๋ฅผ ์ฐธ๊ณ )
$ kubectl run nginx --image=nginx
$ kubectl exec -it nginx -- sh
# <on some pod>
while true; do curl "http://helloworld.default:5000/hello"; done
v1 5ํ, v2 8ํ. ๊ฑฐ์ ๋ฐ๋ฐ ์ ๋๋ก ๋ผ์ฐํ
๋๋ค!
์๋ , Virtual Service!
๊ทธ๋ผ ์ด์ istio์ Virtual Service๋ก v1๊ณผ v2์ ํธ๋ํฝ ๋น์จ์ ์กฐ์ ํด๋ณด์!
์ผ๋จ ์ง๊ธ์ v1, v2 ๋์ ๊ฐ์ด ์ฐ๋ K8s Service ํ๋๋ง ๊ตฌ์ฑํ๋๋ฐ, ๊ฐ๊ฐ์ผ๋ก ๋ผ์ฐํ
ํ๋ ์๋ก์ด 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
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด Virtual Service๋ฅผ ๊ตฌ์ฑํด์, v1์๋ 20% ํธ๋ํฝ์ด, v2์๋ 80%์ ํธ๋ํฝ์ด ํ๋ฅผ ์ ์๋๋ก ๊ตฌ์ฑํด๋ณด์.
# simple-virtual-service
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: helloworld-vs
spec:
hosts:
- "helloworld.default.svc.cluster.local"
http:
- route:
- destination:
host: helloworld-v1.default.svc.cluster.local
weight: 20 # 20% ํธ๋ํฝ
- destination:
host: helloworld-v2.default.svc.cluster.local
weight: 80 # 80% ํธ๋ํฝ
EOF
์์ Virtual Service๋ฅผ ์์ฑํ ํ์ ๋ค์ nginx Pod์ ์ ์ํด์ ๋ค์ ํธ๋ํฝ์ ํ๋ ค๋ณด์.
$ kubectl get vs
$ kubectl run nginx --image=nginx -it --rm -- sh
# <on nginx pod>
while true; do curl "http://helloworld.default:5000/hello"; sleep 1; done

์์ฐ!! ํธ๋ํฝ์ 20:80 ๋น์จ๋ก ๋ถ์ฐ๋์๋ค!! เดฆเตเดฆเดฟ หอฬ๊ณหอฬ )โง
Gateway์ ํจ๊ป Virtual Service๋ฅผ ๊ตฌ์ฑ
istio์์ ์ ๊ณตํ๋ ์์ ์์๋ helloworld-gateway.yaml๋ผ๋ ํ์ผ์ IngressGateway์ VirtualService๋ฅผ ์ ์ํด์ ์ ๊ณตํ๊ณ ์๋ค.
์ด๋ฒ์๋ IngressGateway์ ํจ๊ป VirtualService๋ฅผ ๊ตฌ์ฑํด๋ณด์.
์ผ๋จ Gateway ์ด๋ ๊ฒ ์ ์ํ์.
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: helloworld-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF
๊ทธ๋ฆฌ๊ณ VirtualService๋ ์ด๋ ๊ฒ ๊ตฌ์ฑํ๋ค. ์ด๋ฒ์๋ ๊ตฌ๋ถ์ ์ํด์ v1:v2๋ฅผ 70:30์ผ๋ก ๊ตฌ์ฑํ์. ์ด๋ฒ์๋ v1 ํธ๋ํฝ์ด ๋ ๋ง๋ค!
# hellworld-vs-with-gateway.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: helloworld-gateway-vs
spec:
hosts:
- "*"
gateways:
- helloworld-gateway
http:
- route:
- destination:
host: helloworld-v1.default.svc.cluster.local
port:
number: 5000
weight: 70 # 70% ํธ๋ํฝ
- destination:
host: helloworld-v2.default.svc.cluster.local
port:
number: 5000
weight: 30 # 30% ํธ๋ํฝ
๊ทธ๋ฆฌ๊ณ ๋ nginx Pod์ ์ ์ํด์ ํธ๋ํฝ์ ํ๋ ค๋ณด์. ๊ทธ๋ฐ๋ฐ ์ด๋ฒ์๋ default ns์ ์๋ helloworld์ Service๊ฐ ์๋๋ผ istio-system ns์ ์๋ istio-ingressgateway์ ํธ๋ํฝ์ ๋ณด๋ด์ผ ํ๋ค.
$ kubectl apply -f helloworld-gateway.yaml
$ kubectl apply -f helloworld-vs-with-gateway.yaml
$ kubectl exec -it nginx -- sh
# <on nginx pod>
while true; do curl "http://istio-ingressgateway.istio-system/hello"; done
Kiali์์ ํธ๋ํฝ์ ํ์ธํด๋ณด๋ฉด,

์์ ! ์ด๋ฒ์๋ istio์ default ingress gateway๋ฅผ ํตํด์ ํธ๋ํฝ์ด ๋ถ์ฐ๋๊ณ ์๋ค! ูฉ(^แ^ )ู
VirtualService์ Gateway ์กฐ๊ธ ๋๋ณด๊ธฐ
์ ๋ถ๋ถ์ VirtualService์ Gateway ๋ฆฌ์์ค์ ๋ํด ์กฐ๊ธ๋ ๊น์ ๋ด์ฉ์ ๋ค๋ฃฌ๋ค. ์ด ๋ถ๋ถ์ ์คํตํด๋ helloworld ์์ ๋ฅผ ์งํํ๋๋ฐ ๋ฌธ์ ๊ฐ ์์ผ๋, Istio์ ์
๋ฌธํ์ง ์ผ๋ง ๋์ง ์์๋ค๋ฉด, ๊ณผ๊ฐํ DestinationRule์ ์ฐ๋ ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ์!
์ฌ๊ธฐ์ ์ ๊น! IngressGateway์ ํจ๊ป ์ฐ๋ฉด์, VirtualService์์ ๋ฐ๋ ๋ถ๋ถ์ hosts์ gateways ๋ถ๋ถ์ด๋ค.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: helloworld-vs-w-gateway
spec:
hosts: # ์๊ธฐ!
- "*"
gateways: # ์๊ธฐ๋!
- helloworld-gateway
...
์ด๋, hosts ๋ถ๋ถ์ *๋ผ๋ ์์ผ๋์นด๋(wildcard)๊ฐ ์ฌ์ฉ๋์๋๋ฐ, ์ด ์์ผ๋์นด๋๋ ์ค์ง gateways ์์ฑ๊ณผ ํจ๊ป ์ธ ์ ์๋ค. ๋ง์ฝ gateways์ ํจ๊ป ์ฐ์ง ์๋๋ค๋ฉด, ์๋์ ์๋ฌ๋ฅผ ๋ณด๊ฒ ๋๋ค.
admission webhook โvalidation.istio.ioโ denied the request:
configuration is invalid: wildcard host * is not allowed for virtual services bound to the mesh gateway
์ด๋, โmesh gatewayโ๋ผ๋ ํํ์ด ๋ฑ์ฅํ๋๋ฐ, ๊ฐ๋จํ๊ฒ ๋งํ์๋ฉด, istio์ ์ ์ฒด sidecar proxy์ ๋ชจ์์ ๋งํ๋ค. ์ฆ, sidecar ์ ์ฒด๋ฅผ ๋์์ผ๋ก ํ ๋๋ wildcard host *๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๋คํํ ์ฐ๋ฆฌ๋ helloworld-gateway๋ผ๊ณ gateway๋ฅผ ๋ช
์ํด์ค์ wildcard host *๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค. wildcard host๋ก ๋ช
์ํ๊ธฐ ๋๋ฌธ์ helloworld-gateway์์ ๋ค์ด์ค๋ ๋ชจ๋ ์์ฒญ์ ์ VirtualService์์ ์ฒ๋ฆฌํ๊ฒ ๋๋ค!
๊ทธ๋ฐ๋ฐ, hosts์ wildcard host *๋ฅผ ์ฐ๋ ๋ถ๋ถ์ ๋ ์๋ค. ๋ฐ๋ก istio Gateway ๋ฆฌ์์ค์ ์ ๋ถ๋ถ์ด๋ค.
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: helloworld-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
hosts:
- "*" # ์๊ธฐ!
Gateway์ spec.servers[].hosts ๋ถ๋ถ์ ingress gateway๊ฐ ๋
ธ์ถํ๋ ํฌํธ๋ฅผ ์ฌ์ฉํ VirtualService์ hosts์ ๋ํ ์กฐ๊ฑด์ ๋ช
์ํ๋ค. ๋ง์ฝ, Gateway serversp[].hosts ๊ฐ์ด *.example.com ์๋ค๋ฉด, dev.example.com๊ณผ prod.example.com๋ฅผ host๋ก ๊ฐ๋ VirtualService๋ ํด๋น Gateway๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง, example.com์ด๋ newexample.com๋ฅผ host๋ก ๊ฐ๋ VirtualService๋ ํด๋น Gateway๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ด๋ฒ ๊ฒฝ์ฐ๋ Gateway์์ wildcard host *๋ก ์ ์ฒด ํ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด๋ค VirtualService๋ helloworld-gateway๋ฅผ ์ฌ์ฉํ ์ ์์๋ค!
์๋ , Destination Rule!
์ด๋ฒ์ DestinationRule ๋ฆฌ์์ค์ VirtualService๋ฅผ ์กฐํฉํด์ ํธ๋ํฝ์ ๋ถ์ฐํด๋ณด์!
์ผ๋จ ์์์ ์์ ์์์ ๋ง๋ค์ด๋๋ ๋ฆฌ์์ค๋ ๋ชจ๋ ์ง์๋์. ์ฒซ ์์ ์์ ๋ง๋ค์ด๋๋ v1, v2์ K8s Service๊น์ง ๋๋ค ์ง์ด๋ค!
kubectl delete vs helloworld-vs-w-gateway
kubectl delete gw helloworld-gateway
kubectl delete svc helloworld-v1 helloworld-v2
์ด์ ์๋์ ๊ฐ์ด DestinationRule์ ์ ์ํ๊ณ apply ํด๋ณด์!
# helloworld-dr.yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: helloworld-dr
spec:
host: helloworld.default.svc.cluster.local
subsets: # subset๋ค์ ์ ์ํ์!
- name: helloworld-v1
labels:
version: v1
- name: helloworld-v2
labels:
version: v2
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด VirtualService๋ฅผ ๊ตฌ์ฑํ๋ค.
# helloworld-vs-w-dr.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: helloworld-vs-w-dr
spec:
hosts:
- "helloworld.default.svc.cluster.local"
http:
- route:
- destination:
host: helloworld.default.svc.cluster.local
subset: helloworld-v1 # ์ด๋ฒ์๋ subset์ ์ด๋ค!
weight: 70 # 70% ํธ๋ํฝ
- destination:
host: helloworld.default.svc.cluster.local
subset: helloworld-v2
weight: 30 # 30% ํธ๋ํฝ
๋ฆฌ์์ค๋ฅผ ๋ง๋ ํ์ ํธ๋ํฝ์ ํ๋ ค์ฃผ๋ฉดโฆ
DestinationRule๋ก ๋ฒ์ ๋ณ subset์ ๋ง๋ค์์ ๋
์์ฐ! ์ด๋ฒ์๋ ํธ๋ํฝ์ด ๋น์จ๋๋ก ์ ๋ถ์ฐ๋์๋ค!! ๋๋ผ์ด ์ ์ ๊ฐ ๋ฒ์ ์ ๋์๋๋ K8s Service๋ฅผ ๋ง๋ค์ง ์๊ณ , DestinationRule์์ selector๋ก subset์ ๋ง๋ค๊ธฐ๋ง ํ๋ ๊ฒ์ด๋ค!!
๋ฒ์ ์ ๋์๋๋ K8s Service๋ฅผ ๋ง๋ค์์ ๋
๋งบ์๋ง

์ง๊ธ๊น์ง helloworld ์์ ๋ฅผ ํตํด Istio VirtualService, Gateway, DestinationRule์ ์์ฃผ ๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฒ์ ์ตํ๋ค!
Istio๋ผ๋ ๋ ์์ด ์ฒ์๋ณด๋ฉด ๊ฐ ์ปดํฌ๋ํธ๋ค์ด ์ฝ๊ธฐ์ค๊ธฐ ์ฎ์ฌ ์์ฌ์ ํ์ ํ๊ธฐ๊ฐ ์ด๋ ค์ ๋ ๊ฒ ๊ฐ๋ค. ํนํ ์ด๋ฏธ Istio๋ก ์๋น์ค๋ฉ์๊ฐ ๊ตฌ์ถ๋ ์ํ์์ Istio๋ฅผ ๋ฐ์๋ค์ด๋ ค๊ณ ํ๋ ํนํ ๋จธ๋ฆฌ๊ฐ ๋ ๋ณต์กํ๋ ๊ฒ ๊ฐ๋ค (๐ฆนแฏ ๐ฆน)
๋ค์์ผ๋ก Istio์์ ์ ๊ณตํ๋ Book Info ์์ ๋ฅผ ํ๋ฒ ์ค์ตํ๊ณ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํ๋ค. ๊ทธ๋ผ ๋น ์!