Istio シリーズです。
そういえば Ingress Gateway になかなか辿りつかないな。
OutlierDetection 設定
OutlierDetection は DestinationRule に設定するものでドキュメントもそこにあります。
一旦 VirtualService での転送先を v2 だけにします。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin-virtual-service
spec:
hosts:
- httpbin-service
http:
- route:
- destination:
host: httpbin-service
subset: v1
weight: 0
- destination:
host: httpbin-service
subset: v2
weight: 100
EOF
OutlierDetection で Target を Evict するには転送先にいくつかの Pod が必要なので replica 数を増やします。
kubectl scale --replicas=5 deployment/httpbin-deployment-v2
次に、DestinationRule に OutlierDetection を設定します。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin-destination-rule
spec:
host: httpbin-service
trafficPolicy:
outlierDetection:
consecutiveErrors: 3
interval: 10s
baseEjectionTime: 1m
maxEjectionPercent: 100
minHealthPercent: 1
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
EOF
しかし、これはどうやって確認すれば良いのだろうか? envoy の 15000/stats へアクセスしてみるのかな?後でわかります。
httpbin.org は /status/500
とか /status/503
にアクセスすれば任意の status code を返させることができます。/status/503
にアクセスしてみると curl を実行する側の Pod の istio-proxy のログには1つしか出ませんが、転送先は3つの Pod にアクセスがありました。500 や 502, 504 ではどれも転送先でも1つしかログは出ませんでしたし、response_flags は空でした。retry しても 503 の場合は response_flag が URX になっています。response_flag の意味は Envoy のドキュメントにあります。URX
の意味は “The request was rejected because the upstream retry limit (HTTP) or maximum connect attempts (TCP) was reached.” “response_flags”: “UF,URX” と、カンマ区切りで複数入っていることもありました。
{
"authority": "httpbin-service",
"bytes_received": "0",
"bytes_sent": "0",
"downstream_local_address": "10.109.118.31:80",
"downstream_remote_address": "172.17.0.9:54610",
"duration": "79",
"istio_policy_status": "-",
"method": "GET",
"path": "/status/503",
"protocol": "HTTP/1.1",
"request_id": "682de904-a1f8-45ec-bc7e-d755a47a130d",
"requested_server_name": "-",
"response_code": "503",
"response_flags": "URX",
"route_name": "-",
"start_time": "2020-03-08T06:51:32.094Z",
"upstream_cluster": "outbound|80|v2|httpbin-service.default.svc.cluster.local",
"upstream_host": "172.17.0.13:80",
"upstream_local_address": "172.17.0.9:58194",
"upstream_service_time": "78",
"upstream_transport_failure_reason": "-",
"user_agent": "curl/7.58.0",
"x_forwarded_for": "-"
}
転送先のログ
{
"authority": "httpbin-service",
"bytes_received": "0",
"bytes_sent": "0",
"downstream_local_address": "172.17.0.8:80",
"downstream_remote_address": "172.17.0.9:36276",
"duration": "1",
"istio_policy_status": "-",
"method": "GET",
"path": "/status/503",
"protocol": "HTTP/1.1",
"request_id": "682de904-a1f8-45ec-bc7e-d755a47a130d",
"requested_server_name": "outbound_.80_.v2_.httpbin-service.default.svc.cluster.local",
"response_code": "503",
"response_flags": "-",
"route_name": "default",
"start_time": "2020-03-08T06:51:32.094Z",
"upstream_cluster": "inbound|80|http|httpbin-service.default.svc.cluster.local",
"upstream_host": "127.0.0.1:80",
"upstream_local_address": "127.0.0.1:57664",
"upstream_service_time": "1",
"upstream_transport_failure_reason": "-",
"user_agent": "curl/7.58.0",
"x_forwarded_for": "-"
}
{
"authority": "httpbin-service",
"bytes_received": "0",
"bytes_sent": "0",
"downstream_local_address": "172.17.0.10:80",
"downstream_remote_address": "172.17.0.9:44944",
"duration": "2",
"istio_policy_status": "-",
"method": "GET",
"path": "/status/503",
"protocol": "HTTP/1.1",
"request_id": "682de904-a1f8-45ec-bc7e-d755a47a130d",
"requested_server_name": "outbound_.80_.v2_.httpbin-service.default.svc.cluster.local",
"response_code": "503",
"response_flags": "-",
"route_name": "default",
"start_time": "2020-03-08T06:51:32.117Z",
"upstream_cluster": "inbound|80|http|httpbin-service.default.svc.cluster.local",
"upstream_host": "127.0.0.1:80",
"upstream_local_address": "127.0.0.1:57666",
"upstream_service_time": "1",
"upstream_transport_failure_reason": "-",
"user_agent": "curl/7.58.0",
"x_forwarded_for": "-"
}
{
"authority": "httpbin-service",
"bytes_received": "0",
"bytes_sent": "0",
"downstream_local_address": "172.17.0.13:80",
"downstream_remote_address": "172.17.0.9:58194",
"duration": "2",
"istio_policy_status": "-",
"method": "GET",
"path": "/status/503",
"protocol": "HTTP/1.1",
"request_id": "682de904-a1f8-45ec-bc7e-d755a47a130d",
"requested_server_name": "outbound_.80_.v2_.httpbin-service.default.svc.cluster.local",
"response_code": "503",
"response_flags": "-",
"route_name": "default",
"start_time": "2020-03-08T06:51:32.170Z",
"upstream_cluster": "inbound|80|http|httpbin-service.default.svc.cluster.local",
"upstream_host": "127.0.0.1:80",
"upstream_local_address": "127.0.0.1:57668",
"upstream_service_time": "1",
"upstream_transport_failure_reason": "-",
"user_agent": "curl/7.58.0",
"x_forwarded_for": "-"
}
Retry について
Retry の回数などは VirtualService の http.retries.attempts などで設定することができます。Outlier の話から外れちゃうけどここで retries をいじってみます。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin-virtual-service
spec:
hosts:
- httpbin-service
http:
- route:
- destination:
host: httpbin-service
subset: v1
weight: 0
- destination:
host: httpbin-service
subset: v2
weight: 100
retries:
attempts: 10
EOF
curl を実行する Pod で http://localhost:15000/config_dump を確認してみると "num_retries": 10
になりました。"retry_on": "connect-failure,refused-stream,unavailable,cancelled,resource-exhausted,retriable-status-codes"
ということなので、 x-envoy-retriable-status-codes ヘッダーで指定すれば 503 以外でも retry してくれそうです。
"routes": [
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|80|v2|httpbin-service.default.svc.cluster.local",
"timeout": "0s",
"retry_policy": {
"retry_on": "connect-failure,refused-stream,unavailable,cancelled,resource-exhausted,retriable-status-codes"
,
"num_retries": 10,
"retry_host_predicate": [
{
"name": "envoy.retry_host_predicates.previous_hosts"
}
],
"host_selection_retry_max_attempts": "5",
"retriable_status_codes": [
503
]
},
"max_grpc_timeout": "0s"
},
"metadata": {
"filter_metadata": {
"istio": {
"config": "/apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/httpbin-virtual-service"
}
}
},
"decorator": {
"operation": "httpbin-service.default.svc.cluster.local:80/*"
}
}
]
"num_retries": 10
になったことで、合計のアクセス回数が11回になりました。デフォルトは2だったということですね。
次に 502 でも retry されるかどうか x-envoy-retriable-status-codes ヘッダーを試しましたが、、期待の動作にならなりませんでした… 🤔
OutlierDetection を状態を確認しながらテスト
話を OutlierDetection に戻します。istioctl proxy-config
コマンドで OUTLIER CHECK の状態が確認できることがわかりました。
$ istioctl proxy-config endpoint ubuntu-deployment-cc86cc647-vsvbh | egrep '^ENDPOINT|v2\|httpbin'
ENDPOINT STATUS OUTLIER CHECK CLUSTER
172.17.0.10:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.11:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.12:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.13:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.8:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
次のようにして状態を確認しながら /status/503
にアクセスをしてみます。
while : ; do
date
istioctl proxy-config endpoint ubuntu-deployment-cc86cc647-vsvbh \
| egrep '^ENDPOINT|v2\|httpbin'
sleep 3
done
Sun Mar 8 17:49:37 JST 2020
ENDPOINT STATUS OUTLIER CHECK CLUSTER
172.17.0.10:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.11:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.12:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.13:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.8:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
Sun Mar 8 17:49:40 JST 2020
ENDPOINT STATUS OUTLIER CHECK CLUSTER
172.17.0.10:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.11:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.12:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.13:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.8:80 HEALTHY OK outbound|80|v2|httpbin-service.default.svc.cluster.local
Sun Mar 8 17:49:43 JST 2020
ENDPOINT STATUS OUTLIER CHECK CLUSTER
172.17.0.10:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.11:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.12:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.13:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
172.17.0.8:80 HEALTHY FAILED outbound|80|v2|httpbin-service.default.svc.cluster.local
全部 FAILED になった状態でもアクセスできました。一部だけ FAILED の時は OK の Endpoint にだけ送られました。
FAILED となって外されている期間は baseEjectionTime かける eject された回数時間になるようです。
Istio 導入への道シリーズ
- Istio 導入への道 (1) – インストール編
- Istio 導入への道 (2) – サービス間通信編
- Istio 導入への道 (3) – VirtualService 編
- Istio 導入への道 (4) – Fault Injection 編
- Istio 導入への道 (5) – OutlierDetection と Retry 編
- Istio 導入への道 (6) – Ingress Gatway 編
- Istio 導入への道 (7) – 外部へのアクセス / ServiceEntry 編
- Istio 導入への道 (8) – 外部へのアクセスでも Fault Injection 編
- Istio 導入への道 (9) – gRPC でも Fault Injection 編
- Istio 導入への道 (10) – 図解
- Istio 導入への道 (11) – Ingress Gateway で TLS Termination 編