Istio 연습과제 - Traffic Management
docker engine 18.06.2-ce, kubernetes 1.13.4, Istio 1.1.1 , minikube v0.35.0, macOS Mojave 10.14.4(18E226)
minikube 에서 Istio 공식 TASK > Traffic Management 문서 Istio Traffic Management 를 토대로 minikube 환경에서 실행해보고 개인적으로 정리한 내용을 공유합니다.
Configuring Request Routing
이 Task는 다중 microservice에 대한 요청을 다이나믹하게 라우팅하는 예제
개요
- BookInfo 서비스는 화면 Review 부분은 3개의 다른 버전의 microservice로 구성되어 있으며 브라우저에서 /productpage URL에 대해 refresh를 2,3번 할 때마다 reviews 부문이 변경됩니다. 그 이유는 라우딩하기 위한 기본 서비스 버전을 명확히 지정해주지 않았기 때문에 Istio는 모든 버전의 microservice들을 round-robin 방식으로 라우딩
- 시나리오 #1 - 모든 요청 트래픽을 v1 microservice 로 라우딩 합니다.
- 시나리오 #2 - HTTP Header의 값으로 요청을 구분하고 해당 요청에 대해서는 v2 microservice 로 라우팅을 분리합니다.
Destination Rule 적용/확인
-
bookinfo 서비스에 대한 default Destination Rule 적용/확인
-
기본 Gateway, VirtualService, DestinationRule 지정
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
시나리오 #1 실행
모든 요청 트래픽을 v1 microservice 로 라우딩
- 모든 트래픽을 v1으로 라우팅되도록 VirtualService 적용
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
- 브라우저에서 /productpage를 refresh하면 이전처럼 reviews 번갈아 변경되는 것이 아니라 reviews v1이 계속 표시
시나리오 #2 실행
HTTP Header의 값으로 요청을 구분하고 해당 요청에 대해서는 v2 microservice 로 라우팅을 분리
- jason으로 로그인 한 경우(HTTP의 커스텀 헤더로 매치) 는 v2를 아닌 경우는 v1을 display 하도록 reviews 부분 VirtualService 수정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
EOF
- /productpage 에서 오른쪽 상단 로그인 링크를 클릭하고 로그인화면에서 아이디에 “jason” 을 입력하고 로그인
- refresh 하면 v2 microservice(검은색 별)를 표시
Fault Injction
어플리케이션의 자연복원을 테스트하기 위해 오류를 발생시키는 (fault inject) 방법을 보여줍니다.
개요
- BookInfo 어플리케이션은 ratings microservice 조회 제한시간 7초 로 지정되어 있으며 timeout 발생 시 오류 메시지를 표시
- 시나리오 #1 - jason으로 로그인한 경우(HTTP end-user 커스텀 헤더) 만 ratings microservice 조회에 대한 연결지연(7초이내)을 고의로 발생
- 시나리오 #2 - jason으로 로그인한 경우(HTTP end-user 커스텀 헤더) 만 500에러를 고의로 발생
시나리오 #1 실행
ratings microservice 연결지연(7초이내)을 고의로 발생
- jason으로 로그인 한 경우(HTTP의 커스텀 헤더로 매치) 연결지연(7초이내)을 고의로 발생시키도록 ratings microservice의 VirtualService 수정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- headers:
end-user:
exact: jason
fault:
delay:
percentage:
value: 100.0
fixedDelay: 7s
route:
- destination:
host: ratings
subset: v1
- route:
- destination:
host: ratings
subset: v1
EOF
- /productpage 에서 로그인 안한 상태나 jason이 아닌 아이디로 로그인 했을 경우는 정상 화면 표시
- jason으로 로그인 했을 경우는 7초 deploy 이후 에러 메시지(Sorry, product reviews are currently unavailable for this book.”) 표시
시나리오 #2 실행
ratings microservice 500에러를 고의로 발생
- jason으로 로그인 한 경우(HTTP의 커스텀 헤더로 매치) 500에러를 고의로 발생시키도록 ratings microservice의 VirtualService 수정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- headers:
end-user:
exact: jason
fault:
abort:
percentage:
value: 100.0
httpStatus: 500
route:
- destination:
host: ratings
subset: v1
- route:
- destination:
host: ratings
subset: v1
EOF
- /productpage 에서 로그인 안한 상태나 jason이 아닌 아이디로 로그인 했을 경우는 정상 화면
- jason으로 로그인 했을 경우는 에러메시지(“Ratings service is currently unavailable”) 표시
Traffic Shifting
이 Task는 이전 버전에서 다른 버전으로 트래픽을 서서 마이그레이션 하는 방법을 보여줍니다.
개요
- reviews microservice를 v1, v2를 50:50 확률로 표시한다.
실행
- 모든 트래픽을 v1으로 라우팅되도록 VirtualService 적용
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
- reviews microservice 의 v1 과 v2 를 50:50 으로 라우딩 되도록 VirtualService 적용
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 50
- destination:
host: reviews
subset: v3
weight: 50
EOF
- /productpage 를 reviews 부분이 refresh 하면 v1과 v3(붉은색 별) 화면이 50:50 확률로 표시
TCP Traffic Shifting
이 Task는 이전 버전에서 다른 버전으로 TCP 트래픽을 서서히 마이그레이션 하는 방법을 보여줍니다
개요
- tcp-echo microservice 생성하고 v1 으로 100% 트래픽을 전달한 결과와 v2로 20%를 분산시킨 결과를 비교 확인
실행
- TCP 테스트 어플 설치
$ kubectl apply -f <(istioctl kube-inject -f samples/tcp-echo/tcp-echo-services.yaml)
- TCP traffic to tcp-echo V1 microservice로 전달되도록 Gateway, DestinationRule, VirtualService 적용
$ kubectl apply -f <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: tcp-echo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 31400
name: tcp
protocol: TCP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: tcp-echo-destination
spec:
host: tcp-echo
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: tcp-echo
spec:
hosts:
- "*"
gateways:
- tcp-echo-gateway
tcp:
- match:
- port: 31400
route:
- destination:
host: tcp-echo
port:
number: 9000
subset: v1
EOF
- tcp-echo microservice 로 트래픽 전달하고 결과를 확인
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.clusterIP}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
for i in {1..10}; do \
docker run -e INGRESS_HOST=$INGRESS_HOST -e INGRESS_PORT=$INGRESS_PORT -it --rm busybox sh -c "(date; sleep 1) | nc $INGRESS_HOST $INGRESS_PORT"; \
done
- tcp-echo microservice 의 트래픽을 v2 로 20% 가도록 VirtualService 적용
$ kubectl apply -f <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: tcp-echo
spec:
hosts:
- "*"
gateways:
- tcp-echo-gateway
tcp:
- match:
- port: 31400
route:
- destination:
host: tcp-echo
port:
number: 9000
subset: v1
weight: 80
- destination:
host: tcp-echo
port:
number: 9000
subset: v2
weight: 20
EOF
- tcp-echo microservice 로 트래픽 전달하고 결과를 확인하고 비교
$ for i in {1..10}; do \
docker run -e INGRESS_HOST=$INGRESS_HOST -e INGRESS_PORT=$INGRESS_PORT -it --rm busybox sh -c "(date; sleep 1) | nc $INGRESS_HOST $INGRESS_PORT"; \
done
Setting Request Timeouts
이 TASK는 요청 제한시간를 샛팅하는 방법을 보여줍니다.
개요
- rationgs microservice 에 강제로 delay을 지정하고 reviews microservice 에 제한시간을 지정하여 오류를 확인
실행
- 모든 트래픽을 v1으로 라우팅되도록 VirtualService 적용
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
- reviews 전체 요청을 v2로 라우딩 전환하도록 한다.
~~~
$ kubectl apply -f - «EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews http:
- route:
- destination: host: reviews subset: v2 EOF ~~~
-
브라우저에서 화면 refresh 하여 reviews v2로 라우딩되는지 확인
- rating microservice에 강제로 2초의 deplay를 지정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percent: 100
fixedDelay: 2s
route:
- destination:
host: ratings
subset: v1
EOF
-
브라우저에서 화면을 refresh 하여 2초간의 delay가 되는지 확인
-
reviews v2 서비스에 제한시간을 지정 한다.
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v2
timeout: 0.5s
EOF
- 브라우저 refresh 하면 2초가 지났을 경우 에러메시지 표시 확인
Control Ingress Traffic
이 TASK는 Istio Gateway 를 활용하여 서비스메시 외부에 서비스를 노출하는 방법을 보여줍니다.
개요
- Kubernetes 환경에서
Kubernetes Ingress Resources
는 클러스터 외부에 노출하고자 할 때 명시적인 서비스입니다. 그러나 Istio 서비스메시 환경에서는Istio Gateway
로 불리는 보다 나은 다른 설정 모델 접근법을 사용합니다. - Gateway는 모니터링과 라우팅 룰 같은 Istio 특성들을 클러스터에 들어가는 트래픽에 적용합니다.
- 예제는 Gateway에서 “httpbin.example.com” 도메인만 해당 VirtualService 로 라우팅되고 도메인 정보가 없는 요청은 404(Not Found) 리턴되는 것을 확인합니다.
Istio Gateway 배경 지식
Gateways in an Istio service mesh (출처:https://istio.io/blog/2018/v1alpha3-routing/)
GateWay, VirtualService, DestinationRule (v1alpha3 elements)간 관계
- Gateway
- HTTP/TCP 프로토콜 지정
- TLS 정의 (crt,key)
- MESH 진입 포인트
- DestinationRule
- subset을 정의한다. 이때 라벨링을 통해 정의한 subset에 해당하는 deployment를 지정함 (deployment에만 지정하는 것이 아닐 지도…)
- loadbalancer 등 서비스로 트래픽 정책 결정
- Virtual Service
- 라우팅 룰 적용
- Gateway 로부터 DestinationRule
- Kubernetes service 라우팅 룰을 세분화
- 쿠키, 헤더, uri 등 활용할 수 있음
- 라우팅 룰 적용
- ServiceEntry
- 사용자서비스 Entry 포인트를 등록
- Mesh 밖의 외부 서비스 지정
- 호스트 - 포트(번호, 프로토콜) 별로 지정 가능
- Kubernetes의 Ingress 에서 비즈니스서비스 구간을 3단계로 세분화 하고 각 단계별로 기능을 분리시킴
- 프로토콜 단계 - Protocol, Port, TLS
- 라우팅 단계 ? - Traffic Shifting, Fault Injection , Request Timeout
- LB 단계 ? - 서비스로의 LB
사전준비
- minikube 환경에 istio-ingressgateway 를 NotePort 로 정의했으므로 아래와 같이 IP 와 Port 확인하고 환경변수에 지정
$ export INGRESS_HOST=$(minikube ip)
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
실행
- 호스트명이 “httpbin.example.com”로 요청될 경우 이를 받아주는 Gateway 와 URL profix에 따라 destination을 지정하는 VirtualService를 생성(적용)
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
- /status/200 로 요청한 경우는 Code 200 (정상) 리턴되지만 /headers 와 같이 VirtualService에 정의되지 않는 prefix로 요청한 경우는 Code 404 (Not Found) 리턴되는 것을 확인
$ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/status/200
$ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/headers
- /status/200 요청이지만 도메인정보가 없기 때문에 200 대신 404를 리턴되는 것을 확인한다. Gateway에서 블럭
$ curl -I http://$INGRESS_HOST:$INGRESS_PORT/status/200
Securing Ingress Gateway (File Mount-based approch)
이 TASK 는 File Mount-Based 접근방식을 통해 Istio Ingress Gateway 에서 TLS(SSL)를 적용하는 방법을 보여줍니다.
개요
- 시나리오 #1 - TLS (SIMPLE) 설정
- 시나리오 #2 - mutual TLS 설정
- 시나리오 #3 - 멀티 호스트 TLS 설정
준비
- 이전 사용했던 gateway와 virtualservice 삭제
kubectl delete virtualservice httpbin
kubectl delete gateway httpbin-gateway
- 공통으로 사용할 virtualservice 신규 생성
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
- 클라이언트/서버 인증서 생성
- certificates and keys를 생성할 툴을 clone 하고
generate.sh
실행하고 프롬프트 나오면 모두 y 선택 - 1_root, 2_intermediate, 3_application, 4_client 4게의 서버와 클라이언트 certification 디렉토리가 생성
cd .. git clone https://github.com/nicholasjackson/mtls-go-example cd mtls-go-example/ ./generate.sh httpbin.example.com password1234
- Istio Ingress Gateway 에 마운트 시킬 certification 디렉토리를 새로 생성하고 generate 결과물들을 해당 디렉토리로 이동
mkdir ~+1/httpbin.example.com mv 1_root 2_intermediate 3_application 4_client ~+1/httpbin.example.com cd ~+1/
- certificates and keys를 생성할 툴을 clone 하고
- 공통으로 사용할 IP, PORT 변수 확인
export INGRESS_HOST=$(minikube ip)
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
echo $INGRESS_HOST $SECURE_INGRESS_PORT
시나리오 #1 실행 - TLS (SIMPLE)
File Mount-Based 접근방식을 통해 TLS ingress gateway (SIMPLE) 설정
- “istio-ingressgateway-certs” 란 이름으로 secret tls 생성
$ kubectl create -n istio-system secret tls istio-ingressgateway-certs --key httpbin.example.com/3_application/private/httpbin.example.com.key.pem --cert httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
- istio-system 네임스페이스에 istio-ingressgateway-certs 라는 secret 를 kubectl로 생성하면 istio-gateway는 자동으로 secret을 로드
- 반드시 “istio-ingressgateway-certs” 라는 secret이라고 이름을 지정해야 default ingress gateway 에서 사용할 수 있습니다. (Istio 설치시 설정 옵션 default 값)
-
secret위치도 ingress gateway 파드의 “/etc/istio/ingressgateway-certs/” 에 고정 (Istio 설치시 설정 옵션 default 값)
- secret 생성 확인 secret은
/etc/istio/ingressgateway-certs
위치에 마운트
$ kubectl exec -it -n istio-system $(kubectl -n istio-system get pods -l istio=ingressgateway -o jsonpath='{.items[0].metadata.name}') -- ls -al /etc/istio/ingressgateway-certs
- Gateway 생성
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
hosts:
- "httpbin.example.com"
EOF
- 실행 및 결과확인
curl -v -HHost:httpbin.example.com \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
시나리오 #2 실행 - mutual TLS
File Mount-Based 접근방식을 통해 mutual TLS ingress gateway 설정
- “istio-ingressgateway-ca-certs” 란 이름으로 secret tls 생성 및 확인
$ kubectl create -n istio-system secret generic istio-ingressgateway-ca-certs --from-file=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem
- Gateway 생성
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: MUTUAL
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
caCertificates: /etc/istio/ingressgateway-ca-certs/ca-chain.cert.pem
hosts:
- "httpbin.example.com"
EOF
- 실행
curl -HHost:httpbin.example.com \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
--cert httpbin.example.com/4_client/certs/httpbin.example.com.cert.pem \
--key httpbin.example.com/4_client/private/httpbin.example.com.key.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
시나리오 #3 실행 - 다중 호스트
- gateway는 ingress gateway 파드에서 실행
- 멀티 도메인을 활용할 경우 인증서를 추가하게 되면 해당 인증서를 ingress gateway 파드에 새로 마운트 해주어야 합니다.
- 아래는 디렉터리를 추가로 마운트하기 위해서 helm으로 ingressgateway yaml 을 신규 생성하여 설치하는 예
$ helm template $HOME/istio-fetch/istio --name istio --namespace istio-system -x charts/gateways/templates/deployment.yaml --set gateways.istio-egressgateway.enabled=false \
--set 'gateways.istio-ingressgateway.secretVolumes[0].name'=ingressgateway-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[0].secretName'=istio-ingressgateway-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[0].mountPath'=/etc/istio/ingressgateway-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[1].name'=ingressgateway-ca-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[1].secretName'=istio-ingressgateway-ca-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[1].mountPath'='/etc/istio/ingressgateway-ca-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[2].name'=ingressgateway-bookinfo-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[2].secretName'=istio-ingressgateway-bookinfo-certs \
--set 'gateways.istio-ingressgateway.secretVolumes[2].mountPath'=/etc/istio/ingressgateway-bookinfo-certs > \
$HOME/istio-ingressgateway.yaml
$ kubectl apply -f $HOME/istio-ingressgateway.yaml
Securing Gateways with HTTPS Using Secret Discovery Service
이 TASK 는 SDS(Secret Discovery Service)를 사용하여 Istio Ingress Gateway 에서 TLS(SSL)를 적용하는 방법을 보여줍니다.
- gateways.istio-egressgateway.enabled=false로 gateways.istio-ingressgateway.sds.enabled=true 로 변경하여 istio-ingressgateway yaml을 생성한후 적용
$ helm template install/kubernetes/helm/istio/ --name istio \
--namespace istio-system -x charts/gateways/templates/deployment.yaml \
--set gateways.istio-egressgateway.enabled=false \
--set gateways.istio-ingressgateway.sds.enabled=true > \
$HOME/istio-ingressgateway.yaml
$ kubectl apply -f $HOME/istio-ingressgateway.yaml
- TODO - https://istio.io/docs/tasks/traffic-management/secure-ingress/sds/
Control Egress Traffic
Istio 에서 관리되는 파드들의 모든 outbound 트래픽은 기본적으로 sidecar proxy로 리디렉션되기 때문에, 클러스터 외부의 URL 접근성은 proxy의 구성에 따라 달라집니다.
개요
- 설정하지 않았다면 서비스메시 내의 외부 요청은 envoy proxy 에서 모두 허용
- ServiceEntries 설정을 통하여 외부 서비스 컨트럴 접근 통제를 제공
-
IP 범위 설정으로 bypass 처리
- 시나리오 #1 - Envoy를 통한 외부 서비스 접근 옵션을 조회하고 외부 접근이 가능한지 확인
- 시나리오 #2 - 외부 서비스 접근 정책을 REGISTRY_ONLY 로 변경하고 외부 접근이 불가능한지 확인
- 시나리오 #3 - 외부 서비스 접근 정책 REGISTRY_ONLYHTTP 상태에서 ServiceEntry 등록을 통해 외부 가능 서비스 등록
- 시나리오 #4 - 외부 서비스 호출시 제한시간을 설정
준비작업
- 샘플 어플 설치하고 해당 파드이름을 환경변수 SOURCE_POD 에 지정
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
시나리오 #1 실행
Envoy를 통한 외부 서비스 접근 옵션을 조회하고 외부 접근이 가능한지 확인
- 현재 설정된 외부접근 옵션 확인 (default : ALLOW_ANY)
$ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY"
- ALLOW_ANY 상태에서 외부 서비스 호출 가능 여부 확인
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.google.com | grep "HTTP/"; kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://edition.cnn.com | grep "HTTP/"
- 모두 200 출력하여 호출가능상태임을 확인
시나리오 #2 실행
외부 서비스 접근 정책을 REGISTRY_ONLY 로 변경하고 외부 접근이 불가능한지 확인
- global.outboundTrafficPolicy.mode를 REGISTRY_ONLY로 변경하여 재 설정, 변경에 시간이 걸립니다.
$ kubectl get configmap istio -n istio-system --export -o yaml | sed 's/mode: ALLOW_ANY/mode: REGISTRY_ONLY/g' | kubectl replace -n istio-system -f -
- 외부 서비스 호출 가능 여부 확인
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.google.com | grep "HTTP/"; kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://edition.cnn.com | grep "HTTP/"
- 외부 서비스가 막혀
command terminated with exit code 35
메시지가 표시
시나리오 #3
외부 서비스 접근 정책 REGISTRY_ONLYHTTP 상태에서 ServiceEntry 등록을 통해 외부 가능 서비스 등록
-
외부접근 기본값이 REGISTRY_ONLY 로 지정된 경우 외부 HTTP, HTTPS 서비스에 접근하기 위해서는 접근 호스트, 프로토콜별 ServiceEntry 를 생성
-
외부접근을 위한 ServiceEntry 생성하고 외부서비스로는 httpbin.org (http://httpbin.org) 를 지정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
- 등록된 ServiceEntry에 대해 서비스 가능 여부를 확인한다. 이때 반영시간이 있으므로 주의
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -I http://httpbin.org/status/200
$ kubectl exec -it $SOURCE_POD -c sleep -- curl https://httpbin.org/headers
-
ServiceEntry 에 설정된대로 HTTP는 정상호출, HTTPS 호출 블가능(Code 35)함을 확인
-
외부 서비스 httpbin.org 에 HTTPS 허용으로 변경
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
EOF
- 등록된 ServiceEntry에 대해 서비스 가능 여부를 확인한다. 이때 반영시간이 있으므로 주의
kubectl exec -it $SOURCE_POD -c sleep -- curl https://httpbin.org/headers
kubectl exec -it $SOURCE_POD -c sleep -- curl -I http://httpbin.org/status/200
- ServiceEntry 에 설정된대로 HTTP는 호출불가(code 404), HTTPS 호출 가능함을 확인
시나리오 #4
외부 서비스 호출시 제한시간을 설정
- sleep 파드에서 5초 delay 되는 request를 요청하면 5초후 정상 결과 리턴 (200번)
$ kubectl exec -it $SOURCE_POD -c sleep sh
$ time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
$ exit
- VirtualService 에 httpbin.org 외부서비스 요청에 제한시간 3 초를 지정
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
http:
- timeout: 3s
route:
- destination:
host: httpbin.org
weight: 100
EOF
- 앞서 실행했던 sleep 파드에서 5초 delay 되는 request를 요청하면 이전과 달리 제한시간으로 지정된 약 3초 후 오류코드 503 가 표시
$ kubectl exec -it $SOURCE_POD -c sleep sh
$ time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
$ exit
Circuit Breaking
이 TASK는 연결,요청에 따른 circuit breaking 설정을 보여줍니다.
- Circuit breaker 패턴
- 연결되는 서비스간 장애전파를 막기 위한 패턴
- 마이크로 서비스 아키텍쳐는 여러개의 마이크로 서비스간에 호출하는 개념을 가지고 있으므로 하나의 마이크로서비스가 느려지거나 장애가 나면 종속된 서비스까지 그 장애가 전파되는 특성을 가지고 있습니다.
- 호출되는 서비와 호출하는 서비스 중간에 위치하여 정상적인 상황에서는 트래픽을 문제 없이 bypass 하다가 호출되는 서비스에 문제가 발생했을 경우 트래픽을 강제적으로 끊어서 쓰레드들이 더 이상 요청을 기다리지 않도록해 장애가 전파하는 것을 방지합니다.
개요
- DestinationRule 에 허용 연결과 요청수를 작게한 후 클라이언트(fortio) 에서 서버(httpbin) 로 연결정보 및 요청수를 늘려가면서 circuit breaking 되는 현상을 확인
실행
- Circuit Breaking 상황을 발생시키기 위해 Destination Rule 적용
- maxConnections: 1 and http1MaxPendingRequests: 1
- 1개의 커넥션과 1개 동시요청이 넘을 경우 istio-proxy가 추가요청을 연결을 하게되어 오류 발생
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutiveErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
EOF
- httpbin으로 요청하고 결과를 측정할 클라이언트 어플(fortio) 설치
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/sample-client/fortio-deploy.yaml)
- 결과 확인위해 클라이언트(Fortio)에서 서비스(httpbin)으로 단건 요청해보면 200 코드 결과를 리턴
$ export FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
# kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -curl http://httpbin:8000/get
- 클라이언트(Fortio)에서 서비스(httpbin) 커넥션과 Request 수를 늘려가면서 요청성공(Code 200)과 실패(code 503) 결괄를 확인
$ kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
$ kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -c 3 -qps 0 -n 30 -loglevel Warning http://httpbin:8000/get
- 클라이언트(Frotio) 파드에서 상태값 중에서 httpbin 에 호출값 중 pending 상태 값을 조회
- 결과중
upstream_rq_pending_overflow
값이 circuit breaking 수행 결과
$ kubectl exec -it $FORTIO_POD -c istio-proxy -- sh -c 'curl localhost:15000/stats' | grep httpbin | grep pending
Mirroring (Traffic Mirroring, Shadowing)
이 TASK는 Istio의 트래픽 미러링 역량을 보여줍니다.
개요
- 미러링 할 2개의 microservice(httpbin) 를 준비하고 클라이언트 역할을 할 sleep 서비스를 준비
준비작업
- 미러링 될 microservice 2개(httpbin-v1, httpbin-v2)를 준비
$ cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: httpbin-v1
spec:
replicas: 1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
ports:
- containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: httpbin-v2
spec:
replicas: 1
template:
metadata:
labels:
app: httpbin
version: v2
spec:
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
EOF
- 클라이언트 역할을 할 sleep 어플를 준비
$ cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
template:
metadata:
labels:
app: sleep
spec:
containers:
- name: sleep
image: tutum/curl
command: ["/bin/sleep","infinity"]
imagePullPolicy: IfNotPresent
EOF
실행
- 모든 트래픽을 httpbin-v1 으로 라우딩하도록 지정하기 위해서 DestinationRule 과 VirtualService 적용
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin
http:
- route:
- destination:
host: httpbin
subset: v1
weight: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
EOF
- sleep 파드에서 httpbin 으로 요청 (2회 이상)
$ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
$ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl http://httpbin:8000/headers'
- V2 파드에는 요청 로그가 없음을 확인
$ export V1_POD=$(kubectl get pod -l app=httpbin,version=v1 -o jsonpath={.items..metadata.name})
$ export V2_POD=$(kubectl get pod -l app=httpbin,version=v2 -o jsonpath={.items..metadata.name})
$ kubectl logs -f $V1_POD -c httpbin | grep "GET /headers"
$ kubectl logs -f $V1_POD -c httpbin | grep "GET /headers"
- httpbin-v2로 미러링 되도록 VirtualService 수정 적용
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin
http:
- route:
- destination:
host: httpbin
subset: v1
weight: 100
mirror:
host: httpbin
subset: v2
EOF
- 동일한 방식으로 sleep 파드에서 httpbin 으로 요청 (2회 이상) 트래픽을 전달
$ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl http://httpbin:8000/headers' | python -m json.tool
$ httpbin-v2 파드에서 v1로가는 미러링 요청을 확인
$ kubectl logs -f $V1_POD -c httpbin
$ kubectl logs -f $V2_POD -c httpbin
posted at 2019/04/11 18:10